diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-06 11:14:33 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-06 11:14:33 -0700 |
commit | 4de9ad9bc08b4953fc03336ad38908496e2f8826 (patch) | |
tree | bd44add223061a58317034a0d6c9686d95d12fba /drivers/tty/hvc | |
parent | 576c25eb5954035b64112188d9a2683144600f3d (diff) | |
parent | 06da6629e68ddc8ffe2933d33b3681f09104b3f1 (diff) | |
download | linux-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.c | 149 |
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); |