arch/x86/pci/irq.c

Source file repositories/reference/linux-study-clean/arch/x86/pci/irq.c

File Facts

System
Linux kernel
Corpus path
arch/x86/pci/irq.c
Extension
.c
Size
49086 bytes
Lines
1811
Domain
Architecture Layer
Bucket
arch/x86
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

struct irq_router {
	char *name;
	u16 vendor, device;
	int (*get)(struct pci_dev *router, struct pci_dev *dev, int pirq);
	int (*set)(struct pci_dev *router, struct pci_dev *dev, int pirq,
		int new);
	int (*lvl)(struct pci_dev *router, struct pci_dev *dev, int pirq,
		int irq);
};

struct irq_router_handler {
	u16 vendor;
	int (*probe)(struct irq_router *r, struct pci_dev *router, u16 device);
};

int (*pcibios_enable_irq)(struct pci_dev *dev) = pirq_enable_irq;
void (*pcibios_disable_irq)(struct pci_dev *dev) = pirq_disable_irq;

/*
 *  Check passed address for the PCI IRQ Routing Table signature
 *  and perform checksum verification.
 */

static inline struct irq_routing_table *pirq_check_routing_table(u8 *addr,
								 u8 *limit)
{
	struct irq_routing_table *rt;
	int i;
	u8 sum;

	rt = (struct irq_routing_table *)addr;
	if (rt->signature != PIRQ_SIGNATURE ||
	    rt->version != PIRQ_VERSION ||
	    rt->size % 16 ||
	    rt->size < sizeof(struct irq_routing_table) ||
	    (limit && rt->size > limit - addr))
		return NULL;
	sum = 0;
	for (i = 0; i < rt->size; i++)
		sum += addr[i];
	if (!sum) {
		DBG(KERN_DEBUG "PCI: Interrupt Routing Table found at 0x%lx\n",
		    __pa(rt));
		return rt;
	}
	return NULL;
}

/*
 * Handle the $IRT PCI IRQ Routing Table format used by AMI for its BCP
 * (BIOS Configuration Program) external tool meant for tweaking BIOS
 * structures without the need to rebuild it from sources.  The $IRT
 * format has been invented by AMI before Microsoft has come up with its
 * $PIR format and a $IRT table is therefore there in some systems that
 * lack a $PIR table.
 *
 * It uses the same PCI BIOS 2.1 format for interrupt routing entries
 * themselves but has a different simpler header prepended instead,
 * occupying 8 bytes, where a `$IRT' signature is followed by one byte
 * specifying the total number of interrupt routing entries allocated in
 * the table, then one byte specifying the actual number of entries used
 * (which the BCP tool can take advantage of when modifying the table),
 * and finally a 16-bit word giving the IRQs devoted exclusively to PCI.
 * Unlike with the $PIR table there is no alignment guarantee.
 *
 * Given the similarity of the two formats the $IRT one is trivial to
 * convert to the $PIR one, which we do here, except that obviously we
 * have no information as to the router device to use, but we can handle
 * it by matching PCI device IDs actually seen on the bus against ones
 * that our individual routers recognise.
 *
 * Reportedly there is another $IRT table format where a 16-bit word
 * follows the header instead that points to interrupt routing entries
 * in a $PIR table provided elsewhere.  In that case this code will not
 * be reached though as the $PIR table will have been chosen instead.
 */
static inline struct irq_routing_table *pirq_convert_irt_table(u8 *addr,
							       u8 *limit)
{
	struct irt_routing_table *ir;
	struct irq_routing_table *rt;
	u16 size;
	u8 sum;
	int i;

	ir = (struct irt_routing_table *)addr;
	if (ir->signature != IRT_SIGNATURE || !ir->used || ir->size < ir->used)
		return NULL;

	size = struct_size(ir, slots, ir->used);

Annotation

Implementation Notes