summaryrefslogtreecommitdiffstats
path: root/drivers/tty/hvc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-09-06 11:14:33 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-06 11:14:33 -0700
commit4de9ad9bc08b4953fc03336ad38908496e2f8826 (patch)
treebd44add223061a58317034a0d6c9686d95d12fba /drivers/tty/hvc
parent576c25eb5954035b64112188d9a2683144600f3d (diff)
parent06da6629e68ddc8ffe2933d33b3681f09104b3f1 (diff)
downloadlinux-4de9ad9bc08b4953fc03336ad38908496e2f8826.tar.bz2
Merge git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile
Pull Tile arch updates from Chris Metcalf: "These changes bring in a bunch of new functionality that has been maintained internally at Tilera over the last year, plus other stray bits of work that I've taken into the tile tree from other folks. The changes include some PCI root complex work, interrupt-driven console support, support for performing fast-path unaligned data fixups by kernel-based JIT code generation, CONFIG_PREEMPT support, vDSO support for gettimeofday(), a serial driver for the tilegx on-chip UART, KGDB support, more optimized string routines, support for ftrace and kprobes, improved ASLR, and many bug fixes. We also remove support for the old TILE64 chip, which is no longer buildable" * git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile: (85 commits) tile: refresh tile defconfig files tile: rework <asm/cmpxchg.h> tile PCI RC: make default consistent DMA mask 32-bit tile: add null check for kzalloc in tile/kernel/setup.c tile: make __write_once a synonym for __read_mostly tile: remove support for TILE64 tile: use asm-generic/bitops/builtin-*.h tile: eliminate no-op "noatomichash" boot argument tile: use standard tile_bundle_bits type in traps.c tile: simplify code referencing hypervisor API addresses tile: change <asm/system.h> to <asm/switch_to.h> in comments tile: mark pcibios_init() as __init tile: check for correct compiler earlier in asm-offsets.c tile: use standard 'generic-y' model for <asm/hw_irq.h> tile: use asm-generic version of <asm/local64.h> tile PCI RC: add comment about "PCI hole" problem tile: remove DEBUG_EXTRA_FLAGS kernel config option tile: add virt_to_kpte() API and clean up and document behavior tile: support FRAME_POINTER tile: support reporting Tilera hypervisor statistics ...
Diffstat (limited to 'drivers/tty/hvc')
-rw-r--r--drivers/tty/hvc/hvc_tile.c149
1 files changed, 143 insertions, 6 deletions
diff --git a/drivers/tty/hvc/hvc_tile.c b/drivers/tty/hvc/hvc_tile.c
index 7a84a0595477..af8cdaa1dcb9 100644
--- a/drivers/tty/hvc/hvc_tile.c
+++ b/drivers/tty/hvc/hvc_tile.c
@@ -18,16 +18,46 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
#include <linux/types.h>
+#include <asm/setup.h>
+#include <arch/sim_def.h>
+
#include <hv/hypervisor.h>
#include "hvc_console.h"
+static int use_sim_console;
+static int __init sim_console(char *str)
+{
+ use_sim_console = 1;
+ return 0;
+}
+early_param("sim_console", sim_console);
+
+int tile_console_write(const char *buf, int count)
+{
+ if (unlikely(use_sim_console)) {
+ int i;
+ for (i = 0; i < count; ++i)
+ __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC |
+ (buf[i] << _SIM_CONTROL_OPERATOR_BITS));
+ __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC |
+ (SIM_PUTC_FLUSH_BINARY <<
+ _SIM_CONTROL_OPERATOR_BITS));
+ return 0;
+ } else {
+ return hv_console_write((HV_VirtAddr)buf, count);
+ }
+}
+
static int hvc_tile_put_chars(uint32_t vt, const char *buf, int count)
{
- return hv_console_write((HV_VirtAddr)buf, count);
+ return tile_console_write(buf, count);
}
static int hvc_tile_get_chars(uint32_t vt, char *buf, int count)
@@ -44,25 +74,132 @@ static int hvc_tile_get_chars(uint32_t vt, char *buf, int count)
return i;
}
+#ifdef __tilegx__
+/*
+ * IRQ based callbacks.
+ */
+static int hvc_tile_notifier_add_irq(struct hvc_struct *hp, int irq)
+{
+ int rc;
+ int cpu = raw_smp_processor_id(); /* Choose an arbitrary cpu */
+ HV_Coord coord = { .x = cpu_x(cpu), .y = cpu_y(cpu) };
+
+ rc = notifier_add_irq(hp, irq);
+ if (rc)
+ return rc;
+
+ /*
+ * Request that the hypervisor start sending us interrupts.
+ * If the hypervisor returns an error, we still return 0, so that
+ * we can fall back to polling.
+ */
+ if (hv_console_set_ipi(KERNEL_PL, irq, coord) < 0)
+ notifier_del_irq(hp, irq);
+
+ return 0;
+}
+
+static void hvc_tile_notifier_del_irq(struct hvc_struct *hp, int irq)
+{
+ HV_Coord coord = { 0, 0 };
+
+ /* Tell the hypervisor to stop sending us interrupts. */
+ hv_console_set_ipi(KERNEL_PL, -1, coord);
+
+ notifier_del_irq(hp, irq);
+}
+
+static void hvc_tile_notifier_hangup_irq(struct hvc_struct *hp, int irq)
+{
+ hvc_tile_notifier_del_irq(hp, irq);
+}
+#endif
+
static const struct hv_ops hvc_tile_get_put_ops = {
.get_chars = hvc_tile_get_chars,
.put_chars = hvc_tile_put_chars,
+#ifdef __tilegx__
+ .notifier_add = hvc_tile_notifier_add_irq,
+ .notifier_del = hvc_tile_notifier_del_irq,
+ .notifier_hangup = hvc_tile_notifier_hangup_irq,
+#endif
+};
+
+
+#ifdef __tilegx__
+static int hvc_tile_probe(struct platform_device *pdev)
+{
+ struct hvc_struct *hp;
+ int tile_hvc_irq;
+
+ /* Create our IRQ and register it. */
+ tile_hvc_irq = create_irq();
+ if (tile_hvc_irq < 0)
+ return -ENXIO;
+
+ tile_irq_activate(tile_hvc_irq, TILE_IRQ_PERCPU);
+ hp = hvc_alloc(0, tile_hvc_irq, &hvc_tile_get_put_ops, 128);
+ if (IS_ERR(hp)) {
+ destroy_irq(tile_hvc_irq);
+ return PTR_ERR(hp);
+ }
+ dev_set_drvdata(&pdev->dev, hp);
+
+ return 0;
+}
+
+static int hvc_tile_remove(struct platform_device *pdev)
+{
+ int rc;
+ struct hvc_struct *hp = dev_get_drvdata(&pdev->dev);
+
+ rc = hvc_remove(hp);
+ if (rc == 0)
+ destroy_irq(hp->data);
+
+ return rc;
+}
+
+static void hvc_tile_shutdown(struct platform_device *pdev)
+{
+ struct hvc_struct *hp = dev_get_drvdata(&pdev->dev);
+
+ hvc_tile_notifier_del_irq(hp, hp->data);
+}
+
+static struct platform_device hvc_tile_pdev = {
+ .name = "hvc-tile",
+ .id = 0,
+};
+
+static struct platform_driver hvc_tile_driver = {
+ .probe = hvc_tile_probe,
+ .remove = hvc_tile_remove,
+ .shutdown = hvc_tile_shutdown,
+ .driver = {
+ .name = "hvc-tile",
+ .owner = THIS_MODULE,
+ }
};
+#endif
static int __init hvc_tile_console_init(void)
{
- extern void disable_early_printk(void);
hvc_instantiate(0, 0, &hvc_tile_get_put_ops);
add_preferred_console("hvc", 0, NULL);
- disable_early_printk();
return 0;
}
console_initcall(hvc_tile_console_init);
static int __init hvc_tile_init(void)
{
- struct hvc_struct *s;
- s = hvc_alloc(0, 0, &hvc_tile_get_put_ops, 128);
- return IS_ERR(s) ? PTR_ERR(s) : 0;
+#ifndef __tilegx__
+ struct hvc_struct *hp;
+ hp = hvc_alloc(0, 0, &hvc_tile_get_put_ops, 128);
+ return IS_ERR(hp) ? PTR_ERR(hp) : 0;
+#else
+ platform_device_register(&hvc_tile_pdev);
+ return platform_driver_register(&hvc_tile_driver);
+#endif
}
device_initcall(hvc_tile_init);