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

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

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
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ struct parisc_device {
	/* generic info returned from pdc_pat_cell_module() */
	unsigned long	mod_info;	/* PAT specific - Misc Module info */
	unsigned long	pmod_loc;	/* physical Module location */
	unsigned long	mod0;
#endif
	u64		dma_mask;	/* DMA mask for I/O */
	struct device 	dev;
@@ -61,4 +62,6 @@ parisc_get_drvdata(struct parisc_device *d)

extern struct bus_type parisc_bus_type;

int iosapic_serial_irq(struct parisc_device *dev);

#endif /*_ASM_PARISC_PARISC_DEVICE_H_*/
+1 −0
Original line number Diff line number Diff line
@@ -211,6 +211,7 @@ pat_query_module(ulong pcell_loc, ulong mod_index)
	/* REVISIT: who is the consumer of this? not sure yet... */
	dev->mod_info = pa_pdc_cell->mod_info;	/* pass to PAT_GET_ENTITY() */
	dev->pmod_loc = pa_pdc_cell->mod_location;
	dev->mod0 = pa_pdc_cell->mod[0];

	register_parisc_device(dev);	/* advertise device */

+27 −11
Original line number Diff line number Diff line
@@ -811,18 +811,28 @@ int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
	return pcidev->irq;
}

static struct iosapic_info *first_isi = NULL;
static struct iosapic_info *iosapic_list;

#ifdef CONFIG_64BIT
int iosapic_serial_irq(int num)
int iosapic_serial_irq(struct parisc_device *dev)
{
	struct iosapic_info *isi = first_isi;
	struct irt_entry *irte = NULL;  /* only used if PAT PDC */
	struct iosapic_info *isi;
	struct irt_entry *irte;
	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 */
	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",
		irte,
@@ -834,11 +844,17 @@ int iosapic_serial_irq(int num)
		irte->src_seg_id,
		irte->dest_iosapic_intin,
		(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 */
	vi = isi->isi_vector + isi_line;
	DBG_IRT("iosapic_serial_irq:  line %d vi 0x%p\n", isi_line, vi);
	vi = isi->isi_vector + intin;
	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 (vi->irte)
@@ -941,8 +957,8 @@ void *iosapic_register(unsigned long hpa)
		vip->irqline = (unsigned char) cnt;
		vip->iosapic = isi;
	}
	if (!first_isi)
		first_isi = isi;
	isi->isi_next = iosapic_list;
	iosapic_list = isi;
	return isi;
}

+1 −2
Original line number Diff line number Diff line
@@ -31,9 +31,8 @@ static int __init serial_init_chip(struct parisc_device *dev)
	int err;

#ifdef CONFIG_64BIT
	extern int iosapic_serial_irq(int cellnum);
	if (!dev->irq && (dev->id.sversion == 0xad))
		dev->irq = iosapic_serial_irq(dev->mod_index-1);
		dev->irq = iosapic_serial_irq(dev);
#endif

	if (!dev->irq) {