// SPDX-License-Identifier: GPL-2.0
/*
* Low-Level PCI Support for PC -- Routing of Interrupts
*
* (c) 1999--2000 Martin Mares <mj@ucw.cz>
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/dmi.h>
#include <linux/io.h>
#include <linux/smp.h>
#include <linux/spinlock.h>
#include <asm/io_apic.h>
#include <linux/irq.h>
#include <linux/acpi.h>
#include <asm/i8259.h>
#include <asm/pc-conf-reg.h>
#include <asm/pci_x86.h>
#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
#define PIRQ_VERSION 0x0100
static int broken_hp_bios_irq9;
static int acer_tm360_irqrouting;
static struct irq_routing_table *pirq_table;
static int pirq_enable_irq(struct pci_dev *dev);
static void pirq_disable_irq(struct pci_dev *dev);
/*
* Never use: 0, 1, 2 (timer, keyboard, and cascade)
* Avoid using: 13, 14 and 15 (FP error and IDE).
* Penalize: 3, 4, 6, 7, 12 (known ISA uses: serial, floppy, parallel and mouse)
*/
unsigned int pcibios_irq_mask = 0xfff8;
static int pirq_penalty[16] = {
1000000, 1000000, 1000000, 1000, 1000, 0, 1000, 1000,
0, 0, 0, 0, 1000, 100000, 100000, 100000
};
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)
{
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))
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%p\n",
rt);
return rt;
}
return NULL;
}
/*
* Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table.
*/
static struct irq_routing_table * __init pirq_find_routing_table(void)
{
u8 *addr;
struct irq_routing_table *rt;
if (pirq_table_addr) {
rt = pirq_check_routing_table((u8 *) __va(pirq_table_addr));
if (rt)
return rt;
printk(KERN_WARNING "PCI: PIRQ table NOT found at pirqaddr\n");
}
for (addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) {
rt = pirq_check_routing_table(addr);
if (rt)
return rt;
}
return NULL;
}
/*
* If we have a IRQ routing table, use it to search for peer host
* bridges. It's a gross hack, but since there are no other known
* ways how to get a list of buses, we have to go this way.
*/
static void __init pirq_peer_trick(void)
{
struct irq_routing_table *rt = pirq_table;
u8 busmap[256];
int i;
struct irq_info *e;
memset(busmap, 0, sizeof(busmap));
for (i = 0; i < (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); i++) {
e = &rt->slots[i];
#ifdef DEBUG
{
int j;
DBG(KERN_DEBUG "%02x:%02x slot=%02x", e->bus, e->devfn/8, e->slot);
for (j = 0; j < 4; j++)
DBG(" %d:%02x/%04x", j, e->irq[j].link, e->irq[j].bitmap);
DBG("\n");
}
#endif
busmap[e->bus] = 1;
}
for (i = 1; i < 256; i++) {
if (!busmap[i] || pci_find_bus(0, i))
continue;
pcibios_scan_root(i);
}
pcibios_last_bus = -1;
}
/*
* Code for querying and setting of IRQ routes on various interrupt routers.
* PIC Edge/Level Control Registers (ELCR) 0x4d0 & 0x4d1.
*/
void elcr_set_level_irq(unsigned int irq)
{
unsigned char mask = 1 << (irq & 7);
unsigned int port = PIC_ELCR1 + (irq >> 3);
unsigned char val;
static u16 elcr_irq_mask;
if (irq >= 16 || (1 << irq) & elcr_irq_mask)
return;
elcr_irq_mask |= (1 << irq);
printk(KERN_DEBUG "PCI: setting IRQ %u as level-triggered\n", irq);
val = inb(port);
if (!(val & mask)) {
DBG(KERN_DEBUG " -> edge");
outb(val | mask, port);
}
}
/*
* PIRQ routing for the M1487 ISA Bus Controller (IBC) ASIC used
* with the ALi FinALi 486 chipset. The IBC is not decoded in the
* PCI configuration space, so we identify it by the accompanying
* M1489 Cache-Memory PCI Controller (CMP) ASIC.
*
* There are four 4-bit mappings provided, spread across two PCI
* INTx Routing Table Mapping Registers, available in the port I/O
* space accessible indirectly via the index/data register pair at
* 0x22/0x23, located at indices 0x42 and 0x43 for the INT1/INT2
* and INT3/INT4 lines respectively. The INT1/INT3 and INT2/INT4
* lines are mapped in the low and the high 4-bit nibble of the
* corresponding register as follows:
*
* 0000 : Disabled
* 0001 : IRQ9
* 0010 : IRQ3
* 0011 : IRQ10
* 0100 : IRQ4
* 0101 : IRQ5
* 0110 : IRQ7
* 0111 : IRQ6
* 1000 : Reserved
* 1001 : IRQ11
* 1010 : Reserved
* 1011 : IRQ12
* 1100 : Reserved
* 1101 : IRQ14
* 1110 : Reserved
* 1111 : IRQ15
*
* In addition to the usual ELCR register pair there is a separate
* PCI INTx Sensitivity Register at index 0x44 in the same port I/O
* space, whose bits 3:0 select the trigger mode for INT[4:1] lines
* respectively. Any bit set to 1 causes interrupts coming on the
* corresponding line to be passed to ISA as edge-triggered and
* otherwise they are passed as level-triggered. Manufacturer's
* documentation says this register has to be set consistently with
* the relevant ELCR register.
*
* Accesses to the port I/O space concerned here need to be unlocked
* by writing the value of 0xc5 to the Lock Register at index 0x03
* beforehand. Any other value written to said register prevents
* further accesses from reaching the register file, except for the
* Lock Register being written with 0xc5 again.
*
* References:
*
* "M1489/M1487: 486 PCI Chip Set", Version 1.2, Acer Laboratories
* Inc., July 1997
*/
|