From 4a907dec9845001dc2b117a0ed2a2150384a4cea Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 13 Jun 2007 00:01:04 -0700 Subject: [SPARC64]: Wire up cookie based sun4v interrupt registry. This will be used for logical domain channel interrupts. Signed-off-by: David S. Miller --- arch/sparc64/kernel/irq.c | 131 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 122 insertions(+), 9 deletions(-) (limited to 'arch') diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index a36f8dd0c02..e60d283f60b 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -1,7 +1,6 @@ -/* $Id: irq.c,v 1.114 2002/01/11 08:45:38 davem Exp $ - * irq.c: UltraSparc IRQ handling/init/registry. +/* irq.c: UltraSparc IRQ handling/init/registry. * - * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1997, 2007 David S. Miller (davem@davemloft.net) * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) */ @@ -43,6 +42,7 @@ #include #include #include +#include /* UPA nodes send interrupt packet to UltraSparc with first data reg * value low 5 (7 on Starfire) bits holding the IRQ identifier being @@ -380,6 +380,76 @@ static void sun4v_irq_end(unsigned int virt_irq) } } +static void sun4v_virq_enable(unsigned int virt_irq) +{ + struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); + unsigned int ino = bucket - &ivector_table[0]; + + if (likely(bucket)) { + unsigned long cpuid, dev_handle, dev_ino; + int err; + + cpuid = irq_choose_cpu(virt_irq); + + dev_handle = ino & IMAP_IGN; + dev_ino = ino & IMAP_INO; + + err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid); + if (err != HV_EOK) + printk("sun4v_vintr_set_target(%lx,%lx,%lu): " + "err(%d)\n", + dev_handle, dev_ino, cpuid, err); + err = sun4v_vintr_set_state(dev_handle, dev_ino, + HV_INTR_ENABLED); + if (err != HV_EOK) + printk("sun4v_vintr_set_state(%lx,%lx," + "HV_INTR_ENABLED): err(%d)\n", + dev_handle, dev_ino, err); + } +} + +static void sun4v_virq_disable(unsigned int virt_irq) +{ + struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); + unsigned int ino = bucket - &ivector_table[0]; + + if (likely(bucket)) { + unsigned long dev_handle, dev_ino; + int err; + + dev_handle = ino & IMAP_IGN; + dev_ino = ino & IMAP_INO; + + err = sun4v_vintr_set_state(dev_handle, dev_ino, + HV_INTR_DISABLED); + if (err != HV_EOK) + printk("sun4v_vintr_set_state(%lx,%lx," + "HV_INTR_DISABLED): err(%d)\n", + dev_handle, dev_ino, err); + } +} + +static void sun4v_virq_end(unsigned int virt_irq) +{ + struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); + unsigned int ino = bucket - &ivector_table[0]; + + if (likely(bucket)) { + unsigned long dev_handle, dev_ino; + int err; + + dev_handle = ino & IMAP_IGN; + dev_ino = ino & IMAP_INO; + + err = sun4v_vintr_set_state(dev_handle, dev_ino, + HV_INTR_STATE_IDLE); + if (err != HV_EOK) + printk("sun4v_vintr_set_state(%lx,%lx," + "HV_INTR_STATE_IDLE): err(%d)\n", + dev_handle, dev_ino, err); + } +} + static void run_pre_handler(unsigned int virt_irq) { struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); @@ -434,6 +504,21 @@ static struct irq_chip sun4v_msi = { }; #endif +static struct irq_chip sun4v_virq = { + .typename = "vsun4v", + .enable = sun4v_virq_enable, + .disable = sun4v_virq_disable, + .end = sun4v_virq_end, +}; + +static struct irq_chip sun4v_virq_ack = { + .typename = "vsun4v+ack", + .enable = sun4v_virq_enable, + .disable = sun4v_virq_disable, + .ack = run_pre_handler, + .end = sun4v_virq_end, +}; + void irq_install_pre_handler(int virt_irq, void (*func)(unsigned int, void *, void *), void *arg1, void *arg2) @@ -447,7 +532,8 @@ void irq_install_pre_handler(int virt_irq, chip = get_irq_chip(virt_irq); if (chip == &sun4u_irq_ack || - chip == &sun4v_irq_ack + chip == &sun4v_irq_ack || + chip == &sun4v_virq_ack #ifdef CONFIG_PCI_MSI || chip == &sun4v_msi #endif @@ -455,7 +541,9 @@ void irq_install_pre_handler(int virt_irq, return; chip = (chip == &sun4u_irq ? - &sun4u_irq_ack : &sun4v_irq_ack); + &sun4u_irq_ack : + (chip == &sun4v_irq ? + &sun4v_irq_ack : &sun4v_virq_ack)); set_irq_chip(virt_irq, chip); } @@ -492,19 +580,18 @@ out: return bucket->virt_irq; } -unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino) +static unsigned int sun4v_build_common(unsigned long sysino, + struct irq_chip *chip) { struct ino_bucket *bucket; struct irq_handler_data *data; - unsigned long sysino; BUG_ON(tlb_type != hypervisor); - sysino = sun4v_devino_to_sysino(devhandle, devino); bucket = &ivector_table[sysino]; if (!bucket->virt_irq) { bucket->virt_irq = virt_irq_alloc(__irq(bucket)); - set_irq_chip(bucket->virt_irq, &sun4v_irq); + set_irq_chip(bucket->virt_irq, chip); } data = get_irq_chip_data(bucket->virt_irq); @@ -529,6 +616,32 @@ out: return bucket->virt_irq; } +unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino) +{ + unsigned long sysino = sun4v_devino_to_sysino(devhandle, devino); + + return sun4v_build_common(sysino, &sun4v_irq); +} + +unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino) +{ + unsigned long sysino, hv_err; + + BUG_ON(devhandle & ~IMAP_IGN); + BUG_ON(devino & ~IMAP_INO); + + sysino = devhandle | devino; + + hv_err = sun4v_vintr_set_cookie(devhandle, devino, sysino); + if (hv_err) { + prom_printf("IRQ: Fatal, cannot set cookie for [%x:%x] " + "err=%lu\n", devhandle, devino, hv_err); + prom_halt(); + } + + return sun4v_build_common(sysino, &sun4v_virq); +} + #ifdef CONFIG_PCI_MSI unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p, unsigned int msi_start, unsigned int msi_end) -- cgit v1.2.3 From 56f5c0bd50e948408ac0fd587b5c89fa7e2a1b6e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 12 Jun 2007 16:54:08 -0700 Subject: [SPARC64]: Fix IO/MEM space sizing for PCI. In pci_determine_mem_io_space(), do not hard code the region sizes. Instead, use the values given to us in the ranges property. Thanks goes to Mikael Petterson for the original Xorg failure bug repoert, and strace dumps from Mikael and Dmitry Artamonow. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci_common.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c index f974fefc3eb..4249214608a 100644 --- a/arch/sparc64/kernel/pci_common.c +++ b/arch/sparc64/kernel/pci_common.c @@ -291,8 +291,9 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm) for (i = 0; i < num_pbm_ranges; i++) { const struct linux_prom_pci_ranges *pr = &pbm_ranges[i]; - unsigned long a; + unsigned long a, size; u32 parent_phys_hi, parent_phys_lo; + u32 size_hi, size_lo; int type; parent_phys_hi = pr->parent_phys_hi; @@ -300,9 +301,14 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm) if (tlb_type == hypervisor) parent_phys_hi &= 0x0fffffff; + size_hi = pr->size_hi; + size_lo = pr->size_lo; + type = (pr->child_phys_hi >> 24) & 0x3; a = (((unsigned long)parent_phys_hi << 32UL) | ((unsigned long)parent_phys_lo << 0UL)); + size = (((unsigned long)size_hi << 32UL) | + ((unsigned long)size_lo << 0UL)); switch (type) { case 0: @@ -313,7 +319,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm) case 1: /* 16-bit IO space, 16MB */ pbm->io_space.start = a; - pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL); + pbm->io_space.end = a + size - 1UL; pbm->io_space.flags = IORESOURCE_IO; saw_io = 1; break; @@ -321,7 +327,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm) case 2: /* 32-bit MEM space, 2GB */ pbm->mem_space.start = a; - pbm->mem_space.end = a + (0x80000000UL - 1UL); + pbm->mem_space.end = a + size - 1UL; pbm->mem_space.flags = IORESOURCE_MEM; saw_mem = 1; break; -- cgit v1.2.3 From fc395f8d589f4f0b3fcdd9b8bb84b7cacf711a4f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 12 Jun 2007 23:56:52 -0700 Subject: [SPARC64]: Fix args to sun4v_ldc_revoke(). First argument is LDC channel ID, then mapping cookie, then the MTE revoke cookie. Signed-off-by: David S. Miller --- arch/sparc64/kernel/entry.S | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index 7d1a11822a1..8059531bf0a 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -2357,8 +2357,9 @@ sun4v_ldc_unmap: nop .size sun4v_ldc_unmap, .-sun4v_ldc_unmap - /* %o0: cookie - * %o1: mte_cookie + /* %o0: channel + * %o1: cookie + * %o2: mte_cookie * * returns %o0: status */ -- cgit v1.2.3