aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Bogendoerfer <tsbogend@alpha.franken.de>2013-07-29 20:02:16 -0400
committerHelge Deller <deller@gmx.de>2013-07-31 17:42:32 -0400
commitdd5e6d6a3db09b16b7c222943977865eead88cc3 (patch)
treeb026782954cdc18bf52c82940a4bb34a076d3cdc
parent5a0ce2dc218ea9a6e659dcc5a4827975cb13104f (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.h3
-rw-r--r--arch/parisc/kernel/inventory.c1
-rw-r--r--drivers/parisc/iosapic.c38
-rw-r--r--drivers/tty/serial/8250/8250_gsc.c3
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
62extern struct bus_type parisc_bus_type; 63extern struct bus_type parisc_bus_type;
63 64
65int 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
814static struct iosapic_info *first_isi = NULL; 814static struct iosapic_info *iosapic_list;
815 815
816#ifdef CONFIG_64BIT 816#ifdef CONFIG_64BIT
817int iosapic_serial_irq(int num) 817int 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) {