int iosapic_fixup_irq()

in iosapic.c [706:798]


int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
{
	struct iosapic_info *isi = isi_obj;
	struct irt_entry *irte = NULL;  /* only used if PAT PDC */
	struct vector_info *vi;
	int isi_line;	/* line used by device */

	if (!isi) {
		printk(KERN_WARNING MODULE_NAME ": hpa not registered for %s\n",
			pci_name(pcidev));
		return -1;
	}

#ifdef CONFIG_SUPERIO
	/*
	 * HACK ALERT! (non-compliant PCI device support)
	 *
	 * All SuckyIO interrupts are routed through the PIC's on function 1.
	 * But SuckyIO OHCI USB controller gets an IRT entry anyway because
	 * it advertises INT D for INT_PIN.  Use that IRT entry to get the
	 * SuckyIO interrupt routing for PICs on function 1 (*BLEECCHH*).
	 */
	if (is_superio_device(pcidev)) {
		/* We must call superio_fixup_irq() to register the pdev */
		pcidev->irq = superio_fixup_irq(pcidev);

		/* Don't return if need to program the IOSAPIC's IRT... */
		if (PCI_FUNC(pcidev->devfn) != SUPERIO_USB_FN)
			return pcidev->irq;
	}
#endif /* CONFIG_SUPERIO */

	/* lookup IRT entry for isi/slot/pin set */
	irte = iosapic_xlate_pin(isi, pcidev);
	if (!irte) {
		printk("iosapic: no IRTE for %s (IRQ not connected?)\n",
				pci_name(pcidev));
		return -1;
	}
	DBG_IRT("iosapic_fixup_irq(): irte %p %x %x %x %x %x %x %x %x\n",
		irte,
		irte->entry_type,
		irte->entry_length,
		irte->polarity_trigger,
		irte->src_bus_irq_devno,
		irte->src_bus_id,
		irte->src_seg_id,
		irte->dest_iosapic_intin,
		(u32) irte->dest_iosapic_addr);
	isi_line = irte->dest_iosapic_intin;

	/* get vector info for this input line */
	vi = isi->isi_vector + isi_line;
	DBG_IRT("iosapic_fixup_irq:  line %d vi 0x%p\n", isi_line, vi);

	/* If this IRQ line has already been setup, skip it */
	if (vi->irte)
		goto out;

	vi->irte = irte;

	/*
	 * Allocate processor IRQ
	 *
	 * XXX/FIXME The txn_alloc_irq() code and related code should be
	 * moved to enable_irq(). That way we only allocate processor IRQ
	 * bits for devices that actually have drivers claiming them.
	 * Right now we assign an IRQ to every PCI device present,
	 * regardless of whether it's used or not.
	 */
	vi->txn_irq = txn_alloc_irq(8);

	if (vi->txn_irq < 0)
		panic("I/O sapic: couldn't get TXN IRQ\n");

	/* enable_irq() will use txn_* to program IRdT */
	vi->txn_addr = txn_alloc_addr(vi->txn_irq);
	vi->txn_data = txn_alloc_data(vi->txn_irq);

	vi->eoi_addr = isi->addr + IOSAPIC_REG_EOI;
	vi->eoi_data = cpu_to_le32(vi->txn_data);

	cpu_claim_irq(vi->txn_irq, &iosapic_interrupt_type, vi);

 out:
	pcidev->irq = vi->txn_irq;

	DBG_IRT("iosapic_fixup_irq() %d:%d %x %x line %d irq %d\n",
		PCI_SLOT(pcidev->devfn), PCI_FUNC(pcidev->devfn),
		pcidev->vendor, pcidev->device, isi_line, pcidev->irq);

	return pcidev->irq;
}