Commit dd5e6d6a authored by Thomas Bogendoerfer's avatar Thomas Bogendoerfer Committed by Helge Deller

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: default avatarThomas Bogendoerfer <tsbogend@alpha.franken.de>
Cc: <stable@vger.kernel.org> # 3.10
Signed-off-by: default avatarHelge Deller <deller@gmx.de>
parent 5a0ce2dc
...@@ -23,6 +23,7 @@ struct parisc_device { ...@@ -23,6 +23,7 @@ struct parisc_device {
/* generic info returned from pdc_pat_cell_module() */ /* generic info returned from pdc_pat_cell_module() */
unsigned long mod_info; /* PAT specific - Misc Module info */ unsigned long mod_info; /* PAT specific - Misc Module info */
unsigned long pmod_loc; /* physical Module location */ unsigned long pmod_loc; /* physical Module location */
unsigned long mod0;
#endif #endif
u64 dma_mask; /* DMA mask for I/O */ u64 dma_mask; /* DMA mask for I/O */
struct device dev; struct device dev;
...@@ -61,4 +62,6 @@ parisc_get_drvdata(struct parisc_device *d) ...@@ -61,4 +62,6 @@ parisc_get_drvdata(struct parisc_device *d)
extern struct bus_type parisc_bus_type; extern struct bus_type parisc_bus_type;
int iosapic_serial_irq(struct parisc_device *dev);
#endif /*_ASM_PARISC_PARISC_DEVICE_H_*/ #endif /*_ASM_PARISC_PARISC_DEVICE_H_*/
...@@ -211,6 +211,7 @@ pat_query_module(ulong pcell_loc, ulong mod_index) ...@@ -211,6 +211,7 @@ pat_query_module(ulong pcell_loc, ulong mod_index)
/* REVISIT: who is the consumer of this? not sure yet... */ /* REVISIT: who is the consumer of this? not sure yet... */
dev->mod_info = pa_pdc_cell->mod_info; /* pass to PAT_GET_ENTITY() */ dev->mod_info = pa_pdc_cell->mod_info; /* pass to PAT_GET_ENTITY() */
dev->pmod_loc = pa_pdc_cell->mod_location; dev->pmod_loc = pa_pdc_cell->mod_location;
dev->mod0 = pa_pdc_cell->mod[0];
register_parisc_device(dev); /* advertise device */ register_parisc_device(dev); /* advertise device */
......
...@@ -811,18 +811,28 @@ int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev) ...@@ -811,18 +811,28 @@ int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
return pcidev->irq; return pcidev->irq;
} }
static struct iosapic_info *first_isi = NULL; static struct iosapic_info *iosapic_list;
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
int iosapic_serial_irq(int num) int iosapic_serial_irq(struct parisc_device *dev)
{ {
struct iosapic_info *isi = first_isi; struct iosapic_info *isi;
struct irt_entry *irte = NULL; /* only used if PAT PDC */ struct irt_entry *irte;
struct vector_info *vi; struct vector_info *vi;
int isi_line; /* line used by device */ int cnt;
int intin;
intin = (dev->mod_info >> 24) & 15;
/* lookup IRT entry for isi/slot/pin set */ /* lookup IRT entry for isi/slot/pin set */
irte = &irt_cell[num]; for (cnt = 0; cnt < irt_num_entry; cnt++) {
irte = &irt_cell[cnt];
if (COMPARE_IRTE_ADDR(irte, dev->mod0) &&
irte->dest_iosapic_intin == intin)
break;
}
if (cnt >= irt_num_entry)
return 0; /* no irq found, force polling */
DBG_IRT("iosapic_serial_irq(): irte %p %x %x %x %x %x %x %x %x\n", DBG_IRT("iosapic_serial_irq(): irte %p %x %x %x %x %x %x %x %x\n",
irte, irte,
...@@ -834,11 +844,17 @@ int iosapic_serial_irq(int num) ...@@ -834,11 +844,17 @@ int iosapic_serial_irq(int num)
irte->src_seg_id, irte->src_seg_id,
irte->dest_iosapic_intin, irte->dest_iosapic_intin,
(u32) irte->dest_iosapic_addr); (u32) irte->dest_iosapic_addr);
isi_line = irte->dest_iosapic_intin;
/* search for iosapic */
for (isi = iosapic_list; isi; isi = isi->isi_next)
if (isi->isi_hpa == dev->mod0)
break;
if (!isi)
return 0; /* no iosapic found, force polling */
/* get vector info for this input line */ /* get vector info for this input line */
vi = isi->isi_vector + isi_line; vi = isi->isi_vector + intin;
DBG_IRT("iosapic_serial_irq: line %d vi 0x%p\n", isi_line, vi); DBG_IRT("iosapic_serial_irq: line %d vi 0x%p\n", iosapic_intin, vi);
/* If this IRQ line has already been setup, skip it */ /* If this IRQ line has already been setup, skip it */
if (vi->irte) if (vi->irte)
...@@ -941,8 +957,8 @@ void *iosapic_register(unsigned long hpa) ...@@ -941,8 +957,8 @@ void *iosapic_register(unsigned long hpa)
vip->irqline = (unsigned char) cnt; vip->irqline = (unsigned char) cnt;
vip->iosapic = isi; vip->iosapic = isi;
} }
if (!first_isi) isi->isi_next = iosapic_list;
first_isi = isi; iosapic_list = isi;
return isi; return isi;
} }
......
...@@ -31,9 +31,8 @@ static int __init serial_init_chip(struct parisc_device *dev) ...@@ -31,9 +31,8 @@ static int __init serial_init_chip(struct parisc_device *dev)
int err; int err;
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
extern int iosapic_serial_irq(int cellnum);
if (!dev->irq && (dev->id.sversion == 0xad)) if (!dev->irq && (dev->id.sversion == 0xad))
dev->irq = iosapic_serial_irq(dev->mod_index-1); dev->irq = iosapic_serial_irq(dev);
#endif #endif
if (!dev->irq) { if (!dev->irq) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment