Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f4266ab4 authored by David S. Miller's avatar David S. Miller
Browse files

[SPARC64] sunhv: Use virtual-devices layer to get interrupt.

parent e77227eb
Loading
Loading
Loading
Loading
+67 −6
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@

#include <asm/hypervisor.h>
#include <asm/spitfire.h>
#include <asm/vdev.h>
#include <asm/irq.h>

#if defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
@@ -407,6 +409,60 @@ static void __init sunhv_console_init(void)
	register_console(&sunhv_console);
}

static int __init hv_console_compatible(char *buf, int len)
{
	while (len) {
		int this_len;

		if (!strcmp(buf, "qcn"))
			return 1;

		this_len = strlen(buf) + 1;

		buf += this_len;
		len -= this_len;
	}

	return 0;
}

static unsigned int __init get_interrupt(void)
{
	const char *cons_str = "console";
	const char *compat_str = "compatible";
	int node = prom_getchild(sun4v_vdev_root);
	unsigned int irq;
	char buf[64];
	int err, len;

	node = prom_searchsiblings(node, cons_str);
	if (!node)
		return 0;

	len = prom_getproplen(node, compat_str);
	if (len == 0 || len == -1)
		return 0;

	err = prom_getproperty(node, compat_str, buf, 64);
	if (err == -1)
		return 0;

	if (!hv_console_compatible(buf, len))
		return 0;

	/* Ok, the this is the OBP node for the sun4v hypervisor
	 * console device.  Decode the interrupt.
	 */
	err = prom_getproperty(node, "interrupts",
			       (char *) &irq, sizeof(irq));
	if (err == -1)
		return 0;

	return sun4v_build_irq(sun4v_vdev_devhandle, irq, 4, 0);
}

static u32 sunhv_irq;

static int __init sunhv_init(void)
{
	struct uart_port *port;
@@ -415,6 +471,10 @@ static int __init sunhv_init(void)
	if (tlb_type != hypervisor)
		return -ENODEV;

	sunhv_irq = get_interrupt();
	if (!sunhv_irq)
		return -ENODEV;

	port = kmalloc(sizeof(struct uart_port), GFP_KERNEL);
	if (unlikely(!port))
		return -ENOMEM;
@@ -424,22 +484,23 @@ static int __init sunhv_init(void)
	port->type = PORT_SUNHV;
	port->uartclk = ( 29491200 / 16 ); /* arbitrary */

	/* XXX Get interrupt. XXX */
	if (request_irq(0 /* XXX */, sunhv_interrupt,
	if (request_irq(sunhv_irq, sunhv_interrupt,
			SA_SHIRQ, "serial(sunhv)", port)) {
		printk("sunhv: Cannot get IRQ %x\n",
		       0 /* XXX */);
		printk("sunhv: Cannot get IRQ %x\n", sunhv_irq);
		kfree(port);
		return -ENODEV;
	}

	printk("SUNHV: SUN4V virtual console, IRQ[%08x]\n",
	       sunhv_irq);

	sunhv_reg.minor = sunserial_current_minor;
	sunhv_reg.nr = 1;
	sunhv_reg.cons = &sunhv_console;

	ret = uart_register_driver(&sunhv_reg);
	if (ret < 0) {
		free_irq(0 /* XXX */, up);
		free_irq(sunhv_irq, up);
		kfree(port);

		return ret;
@@ -463,7 +524,7 @@ static void __exit sunhv_exit(void)
	BUG_ON(!port);

	uart_remove_one_port(&sunhv_reg, port);
	free_irq(0 /* XXX */, port);
	free_irq(sunhv_irq, port);

	sunserial_current_minor -= 1;