diff options
author | Thomas Bogendoerfer <tsbogend@alpha.franken.de> | 2013-07-29 20:02:16 -0400 |
---|---|---|
committer | Helge Deller <deller@gmx.de> | 2013-07-31 17:42:32 -0400 |
commit | dd5e6d6a3db09b16b7c222943977865eead88cc3 (patch) | |
tree | b026782954cdc18bf52c82940a4bb34a076d3cdc | |
parent | 5a0ce2dc218ea9a6e659dcc5a4827975cb13104f (diff) |
parisc: Fix interrupt routing for C8000 serial ports
We can't use dev->mod_index for selecting the interrupt routing entry,
because it's not an index into interrupt routing table. It will be even
wrong on a machine with 2 CPUs (4 cores). But all needed information is
contained in the PAT entries for the serial ports. mod[0] contains the
iosapic address and mod_info has some indications for the interrupt
input (at least it looks like it). This patch implements the searching
for the right iosapic and uses this interrupt input information.
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Cc: <stable@vger.kernel.org> # 3.10
Signed-off-by: Helge Deller <deller@gmx.de>
-rw-r--r-- | arch/parisc/include/asm/parisc-device.h | 3 | ||||
-rw-r--r-- | arch/parisc/kernel/inventory.c | 1 | ||||
-rw-r--r-- | drivers/parisc/iosapic.c | 38 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_gsc.c | 3 |
4 files changed, 32 insertions, 13 deletions
diff --git a/arch/parisc/include/asm/parisc-device.h b/arch/parisc/include/asm/parisc-device.h index 9afdad6c2ffb..eaf4dc1c7294 100644 --- a/arch/parisc/include/asm/parisc-device.h +++ b/arch/parisc/include/asm/parisc-device.h | |||
@@ -23,6 +23,7 @@ struct parisc_device { | |||
23 | /* generic info returned from pdc_pat_cell_module() */ | 23 | /* generic info returned from pdc_pat_cell_module() */ |
24 | unsigned long mod_info; /* PAT specific - Misc Module info */ | 24 | unsigned long mod_info; /* PAT specific - Misc Module info */ |
25 | unsigned long pmod_loc; /* physical Module location */ | 25 | unsigned long pmod_loc; /* physical Module location */ |
26 | unsigned long mod0; | ||
26 | #endif | 27 | #endif |
27 | u64 dma_mask; /* DMA mask for I/O */ | 28 | u64 dma_mask; /* DMA mask for I/O */ |
28 | struct device dev; | 29 | struct device dev; |
@@ -61,4 +62,6 @@ parisc_get_drvdata(struct parisc_device *d) | |||
61 | 62 | ||
62 | extern struct bus_type parisc_bus_type; | 63 | extern struct bus_type parisc_bus_type; |
63 | 64 | ||
65 | int iosapic_serial_irq(struct parisc_device *dev); | ||
66 | |||
64 | #endif /*_ASM_PARISC_PARISC_DEVICE_H_*/ | 67 | #endif /*_ASM_PARISC_PARISC_DEVICE_H_*/ |
diff --git a/arch/parisc/kernel/inventory.c b/arch/parisc/kernel/inventory.c index 3295ef4a185d..f0b6722fc706 100644 --- a/arch/parisc/kernel/inventory.c +++ b/arch/parisc/kernel/inventory.c | |||
@@ -211,6 +211,7 @@ pat_query_module(ulong pcell_loc, ulong mod_index) | |||
211 | /* REVISIT: who is the consumer of this? not sure yet... */ | 211 | /* REVISIT: who is the consumer of this? not sure yet... */ |
212 | dev->mod_info = pa_pdc_cell->mod_info; /* pass to PAT_GET_ENTITY() */ | 212 | dev->mod_info = pa_pdc_cell->mod_info; /* pass to PAT_GET_ENTITY() */ |
213 | dev->pmod_loc = pa_pdc_cell->mod_location; | 213 | dev->pmod_loc = pa_pdc_cell->mod_location; |
214 | dev->mod0 = pa_pdc_cell->mod[0]; | ||
214 | 215 | ||
215 | register_parisc_device(dev); /* advertise device */ | 216 | register_parisc_device(dev); /* advertise device */ |
216 | 217 | ||
diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c index e79e006eb9ab..9ee04b4b68bf 100644 --- a/drivers/parisc/iosapic.c +++ b/drivers/parisc/iosapic.c | |||
@@ -811,18 +811,28 @@ int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev) | |||
811 | return pcidev->irq; | 811 | return pcidev->irq; |
812 | } | 812 | } |
813 | 813 | ||
814 | static struct iosapic_info *first_isi = NULL; | 814 | static struct iosapic_info *iosapic_list; |
815 | 815 | ||
816 | #ifdef CONFIG_64BIT | 816 | #ifdef CONFIG_64BIT |
817 | int iosapic_serial_irq(int num) | 817 | int iosapic_serial_irq(struct parisc_device *dev) |
818 | { | 818 | { |
819 | struct iosapic_info *isi = first_isi; | 819 | struct iosapic_info *isi; |
820 | struct irt_entry *irte = NULL; /* only used if PAT PDC */ | 820 | struct irt_entry *irte; |
821 | struct vector_info *vi; | 821 | struct vector_info *vi; |
822 | int isi_line; /* line used by device */ | 822 | int cnt; |
823 | int intin; | ||
824 | |||
825 | intin = (dev->mod_info >> 24) & 15; | ||
823 | 826 | ||
824 | /* lookup IRT entry for isi/slot/pin set */ | 827 | /* lookup IRT entry for isi/slot/pin set */ |
825 | irte = &irt_cell[num]; | 828 | for (cnt = 0; cnt < irt_num_entry; cnt++) { |
829 | irte = &irt_cell[cnt]; | ||
830 | if (COMPARE_IRTE_ADDR(irte, dev->mod0) && | ||
831 | irte->dest_iosapic_intin == intin) | ||
832 | break; | ||
833 | } | ||
834 | if (cnt >= irt_num_entry) | ||
835 | return 0; /* no irq found, force polling */ | ||
826 | 836 | ||
827 | DBG_IRT("iosapic_serial_irq(): irte %p %x %x %x %x %x %x %x %x\n", | 837 | DBG_IRT("iosapic_serial_irq(): irte %p %x %x %x %x %x %x %x %x\n", |
828 | irte, | 838 | irte, |
@@ -834,11 +844,17 @@ int iosapic_serial_irq(int num) | |||
834 | irte->src_seg_id, | 844 | irte->src_seg_id, |
835 | irte->dest_iosapic_intin, | 845 | irte->dest_iosapic_intin, |
836 | (u32) irte->dest_iosapic_addr); | 846 | (u32) irte->dest_iosapic_addr); |
837 | isi_line = irte->dest_iosapic_intin; | 847 | |
848 | /* search for iosapic */ | ||
849 | for (isi = iosapic_list; isi; isi = isi->isi_next) | ||
850 | if (isi->isi_hpa == dev->mod0) | ||
851 | break; | ||
852 | if (!isi) | ||
853 | return 0; /* no iosapic found, force polling */ | ||
838 | 854 | ||
839 | /* get vector info for this input line */ | 855 | /* get vector info for this input line */ |
840 | vi = isi->isi_vector + isi_line; | 856 | vi = isi->isi_vector + intin; |
841 | DBG_IRT("iosapic_serial_irq: line %d vi 0x%p\n", isi_line, vi); | 857 | DBG_IRT("iosapic_serial_irq: line %d vi 0x%p\n", iosapic_intin, vi); |
842 | 858 | ||
843 | /* If this IRQ line has already been setup, skip it */ | 859 | /* If this IRQ line has already been setup, skip it */ |
844 | if (vi->irte) | 860 | if (vi->irte) |
@@ -941,8 +957,8 @@ void *iosapic_register(unsigned long hpa) | |||
941 | vip->irqline = (unsigned char) cnt; | 957 | vip->irqline = (unsigned char) cnt; |
942 | vip->iosapic = isi; | 958 | vip->iosapic = isi; |
943 | } | 959 | } |
944 | if (!first_isi) | 960 | isi->isi_next = iosapic_list; |
945 | first_isi = isi; | 961 | iosapic_list = isi; |
946 | return isi; | 962 | return isi; |
947 | } | 963 | } |
948 | 964 | ||
diff --git a/drivers/tty/serial/8250/8250_gsc.c b/drivers/tty/serial/8250/8250_gsc.c index bb91b4713ebd..2e3ea1a70d7b 100644 --- a/drivers/tty/serial/8250/8250_gsc.c +++ b/drivers/tty/serial/8250/8250_gsc.c | |||
@@ -31,9 +31,8 @@ static int __init serial_init_chip(struct parisc_device *dev) | |||
31 | int err; | 31 | int err; |
32 | 32 | ||
33 | #ifdef CONFIG_64BIT | 33 | #ifdef CONFIG_64BIT |
34 | extern int iosapic_serial_irq(int cellnum); | ||
35 | if (!dev->irq && (dev->id.sversion == 0xad)) | 34 | if (!dev->irq && (dev->id.sversion == 0xad)) |
36 | dev->irq = iosapic_serial_irq(dev->mod_index-1); | 35 | dev->irq = iosapic_serial_irq(dev); |
37 | #endif | 36 | #endif |
38 | 37 | ||
39 | if (!dev->irq) { | 38 | if (!dev->irq) { |