Subversion Repositories shark

Compare Revisions

Ignore whitespace Rev 435 → Rev 436

/shark/trunk/drivers/newpci/numa.c
0,0 → 1,129
/*
* numa.c - Low-level PCI access for NUMA-Q machines
*/
 
#include <linux/pci.h>
#include <linux/init.h>
#include "pci.h"
 
#define BUS2QUAD(global) (mp_bus_id_to_node[global])
#define BUS2LOCAL(global) (mp_bus_id_to_local[global])
#define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local])
 
#define PCI_CONF1_MQ_ADDRESS(bus, devfn, reg) \
(0x80000000 | (BUS2LOCAL(bus) << 16) | (devfn << 8) | (reg & ~3))
 
static int pci_conf1_mq_read (int seg, int bus, int devfn, int reg, int len, u32 *value)
{
unsigned long flags;
 
if (!value || (bus > MAX_MP_BUSSES) || (devfn > 255) || (reg > 255))
return -EINVAL;
 
spin_lock_irqsave(&pci_config_lock, flags);
 
outl_quad(PCI_CONF1_MQ_ADDRESS(bus, devfn, reg), 0xCF8, BUS2QUAD(bus));
 
switch (len) {
case 1:
*value = inb_quad(0xCFC + (reg & 3), BUS2QUAD(bus));
break;
case 2:
*value = inw_quad(0xCFC + (reg & 2), BUS2QUAD(bus));
break;
case 4:
*value = inl_quad(0xCFC, BUS2QUAD(bus));
break;
}
 
spin_unlock_irqrestore(&pci_config_lock, flags);
 
return 0;
}
 
static int pci_conf1_mq_write (int seg, int bus, int devfn, int reg, int len, u32 value)
{
unsigned long flags;
 
if ((bus > MAX_MP_BUSSES) || (devfn > 255) || (reg > 255))
return -EINVAL;
 
spin_lock_irqsave(&pci_config_lock, flags);
 
outl_quad(PCI_CONF1_MQ_ADDRESS(bus, devfn, reg), 0xCF8, BUS2QUAD(bus));
 
switch (len) {
case 1:
outb_quad((u8)value, 0xCFC + (reg & 3), BUS2QUAD(bus));
break;
case 2:
outw_quad((u16)value, 0xCFC + (reg & 2), BUS2QUAD(bus));
break;
case 4:
outl_quad((u32)value, 0xCFC, BUS2QUAD(bus));
break;
}
 
spin_unlock_irqrestore(&pci_config_lock, flags);
 
return 0;
}
 
#undef PCI_CONF1_MQ_ADDRESS
 
static struct pci_raw_ops pci_direct_conf1_mq = {
.read = pci_conf1_mq_read,
.write = pci_conf1_mq_write
};
 
 
static void __devinit pci_fixup_i450nx(struct pci_dev *d)
{
/*
* i450NX -- Find and scan all secondary buses on all PXB's.
*/
int pxb, reg;
u8 busno, suba, subb;
int quad = BUS2QUAD(d->bus->number);
 
printk("PCI: Searching for i450NX host bridges on %s\n", pci_name(d));
reg = 0xd0;
for(pxb=0; pxb<2; pxb++) {
pci_read_config_byte(d, reg++, &busno);
pci_read_config_byte(d, reg++, &suba);
pci_read_config_byte(d, reg++, &subb);
DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
if (busno)
pci_scan_bus(QUADLOCAL2BUS(quad,busno), &pci_root_ops, NULL); /* Bus A */
if (suba < subb)
pci_scan_bus(QUADLOCAL2BUS(quad,suba+1), &pci_root_ops, NULL); /* Bus B */
}
pcibios_last_bus = -1;
}
 
struct pci_fixup pcibios_fixups[] = {
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx },
};
 
static int __init pci_numa_init(void)
{
int quad;
 
raw_pci_ops = &pci_direct_conf1_mq;
 
if (pcibios_scanned++)
return 0;
 
pci_root_bus = pcibios_scan_root(0);
if (numnodes > 1) {
for (quad = 1; quad < numnodes; ++quad) {
printk("Scanning PCI bus %d for quad %d\n",
QUADLOCAL2BUS(quad,0), quad);
pci_scan_bus(QUADLOCAL2BUS(quad,0),
&pci_root_ops, NULL);
}
}
return 0;
}
 
subsys_initcall(pci_numa_init);
/shark/trunk/drivers/newpci/pci2.h
0,0 → 1,74
/*
* Low-Level PCI Access for i386 machines.
*
* (c) 1999 Martin Mares <mj@ucw.cz>
*/
 
#undef DEBUG
 
#ifdef DEBUG
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#endif
 
#define PCI_PROBE_BIOS 0x0001
#define PCI_PROBE_CONF1 0x0002
#define PCI_PROBE_CONF2 0x0004
#define PCI_NO_SORT 0x0100
#define PCI_BIOS_SORT 0x0200
#define PCI_NO_CHECKS 0x0400
#define PCI_USE_PIRQ_MASK 0x0800
#define PCI_ASSIGN_ROMS 0x1000
#define PCI_BIOS_IRQ_SCAN 0x2000
#define PCI_ASSIGN_ALL_BUSSES 0x4000
#define PCI_NO_ACPI_ROUTING 0x8000
 
extern unsigned int pci_probe;
 
/* pci-i386.c */
 
extern unsigned int pcibios_max_latency;
 
void pcibios_resource_survey(void);
int pcibios_enable_resources(struct pci_dev *, int);
 
/* pci-pc.c */
 
extern int pcibios_last_bus;
extern struct pci_bus *pci_root_bus;
extern struct pci_ops pci_root_ops;
 
/* pci-irq.c */
 
struct irq_info {
u8 bus, devfn; /* Bus, device and function */
struct {
u8 link; /* IRQ line ID, chipset dependent, 0=not routed */
u16 bitmap; /* Available IRQs */
} __attribute__((packed)) irq[4];
u8 slot; /* Slot number, 0=onboard */
u8 rfu;
} __attribute__((packed));
 
struct irq_routing_table {
u32 signature; /* PIRQ_SIGNATURE should be here */
u16 version; /* PIRQ_VERSION */
u16 size; /* Table size in bytes */
u8 rtr_bus, rtr_devfn; /* Where the interrupt router lies */
u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */
u16 rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */
u32 miniport_data; /* Crap */
u8 rfu[11];
u8 checksum; /* Modulo 256 checksum must give zero */
struct irq_info slots[0];
} __attribute__((packed));
 
extern unsigned int pcibios_irq_mask;
 
extern int pcibios_scanned;
extern spinlock_t pci_config_lock;
 
int pirq_enable_irq(struct pci_dev *dev);
 
extern int (*pcibios_enable_irq)(struct pci_dev *dev);
/shark/trunk/drivers/newpci/legacy.c
0,0 → 1,56
/*
* legacy.c - traditional, old school PCI bus probing
*/
#include <linuxcomp.h>
 
#include <linux/init.h>
#include <linux/pci.h>
#include "pci2.h"
 
/*
* Discover remaining PCI buses in case there are peer host bridges.
* We use the number of last PCI bus provided by the PCI BIOS.
*/
static void __devinit pcibios_fixup_peer_bridges(void)
{
int n, devfn;
 
if (pcibios_last_bus <= 0 || pcibios_last_bus >= 0xff)
return;
DBG("PCI: Peer bridge fixup\n");
 
for (n=0; n <= pcibios_last_bus; n++) {
u32 l;
if (pci_find_bus(0, n))
continue;
for (devfn = 0; devfn < 256; devfn += 8) {
if (!raw_pci_ops->read(0, n, devfn, PCI_VENDOR_ID, 2, &l) &&
l != 0x0000 && l != 0xffff) {
DBG("Found device at %02x:%02x [%04x]\n", n, devfn, l);
printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n);
pci_scan_bus(n, &pci_root_ops, NULL);
break;
}
}
}
}
 
static int __init pci_legacy_init(void)
{
if (!raw_pci_ops) {
printk("PCI: System does not support PCI\n");
return 0;
}
 
if (pcibios_scanned++)
return 0;
 
printk("PCI: Probing PCI hardware\n");
pci_root_bus = pcibios_scan_root(0);
 
pcibios_fixup_peer_bridges();
 
return 0;
}
 
subsys_initcall(pci_legacy_init);
/shark/trunk/drivers/newpci/direct.c
0,0 → 1,287
/*
* direct.c - Low-level direct PCI config space access
*/
 
#include <linuxcomp.h>
 
#include <linux/pci.h>
#include <linux/init.h>
#include "pci2.h"
 
/*
* Functions for accessing PCI configuration space with type 1 accesses
*/
 
#define PCI_CONF1_ADDRESS(bus, devfn, reg) \
(0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))
 
static int pci_conf1_read (int seg, int bus, int devfn, int reg, int len, u32 *value)
{
unsigned long flags;
 
if (!value || (bus > 255) || (devfn > 255) || (reg > 255))
return -EINVAL;
 
spin_lock_irqsave(&pci_config_lock, flags);
 
outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8);
 
switch (len) {
case 1:
*value = inb(0xCFC + (reg & 3));
break;
case 2:
*value = inw(0xCFC + (reg & 2));
break;
case 4:
*value = inl(0xCFC);
break;
}
 
spin_unlock_irqrestore(&pci_config_lock, flags);
 
return 0;
}
 
static int pci_conf1_write (int seg, int bus, int devfn, int reg, int len, u32 value)
{
unsigned long flags;
 
if ((bus > 255) || (devfn > 255) || (reg > 255))
return -EINVAL;
 
spin_lock_irqsave(&pci_config_lock, flags);
 
outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8);
 
switch (len) {
case 1:
outb((u8)value, 0xCFC + (reg & 3));
break;
case 2:
outw((u16)value, 0xCFC + (reg & 2));
break;
case 4:
outl((u32)value, 0xCFC);
break;
}
 
spin_unlock_irqrestore(&pci_config_lock, flags);
 
return 0;
}
 
#undef PCI_CONF1_ADDRESS
 
struct pci_raw_ops pci_direct_conf1 = {
.read = pci_conf1_read,
.write = pci_conf1_write,
};
 
 
/*
* Functions for accessing PCI configuration space with type 2 accesses
*/
 
#define PCI_CONF2_ADDRESS(dev, reg) (u16)(0xC000 | (dev << 8) | reg)
 
static int pci_conf2_read(int seg, int bus, int devfn, int reg, int len, u32 *value)
{
unsigned long flags;
int dev, fn;
 
if (!value || (bus > 255) || (devfn > 255) || (reg > 255))
return -EINVAL;
 
dev = PCI_SLOT(devfn);
fn = PCI_FUNC(devfn);
 
if (dev & 0x10)
return PCIBIOS_DEVICE_NOT_FOUND;
 
spin_lock_irqsave(&pci_config_lock, flags);
 
outb((u8)(0xF0 | (fn << 1)), 0xCF8);
outb((u8)bus, 0xCFA);
 
switch (len) {
case 1:
*value = inb(PCI_CONF2_ADDRESS(dev, reg));
break;
case 2:
*value = inw(PCI_CONF2_ADDRESS(dev, reg));
break;
case 4:
*value = inl(PCI_CONF2_ADDRESS(dev, reg));
break;
}
 
outb(0, 0xCF8);
 
spin_unlock_irqrestore(&pci_config_lock, flags);
 
return 0;
}
 
static int pci_conf2_write (int seg, int bus, int devfn, int reg, int len, u32 value)
{
unsigned long flags;
int dev, fn;
 
if ((bus > 255) || (devfn > 255) || (reg > 255))
return -EINVAL;
 
dev = PCI_SLOT(devfn);
fn = PCI_FUNC(devfn);
 
if (dev & 0x10)
return PCIBIOS_DEVICE_NOT_FOUND;
 
spin_lock_irqsave(&pci_config_lock, flags);
 
outb((u8)(0xF0 | (fn << 1)), 0xCF8);
outb((u8)bus, 0xCFA);
 
switch (len) {
case 1:
outb((u8)value, PCI_CONF2_ADDRESS(dev, reg));
break;
case 2:
outw((u16)value, PCI_CONF2_ADDRESS(dev, reg));
break;
case 4:
outl((u32)value, PCI_CONF2_ADDRESS(dev, reg));
break;
}
 
outb(0, 0xCF8);
 
spin_unlock_irqrestore(&pci_config_lock, flags);
 
return 0;
}
 
#undef PCI_CONF2_ADDRESS
 
static struct pci_raw_ops pci_direct_conf2 = {
.read = pci_conf2_read,
.write = pci_conf2_write,
};
 
 
/*
* Before we decide to use direct hardware access mechanisms, we try to do some
* trivial checks to ensure it at least _seems_ to be working -- we just test
* whether bus 00 contains a host bridge (this is similar to checking
* techniques used in XFree86, but ours should be more reliable since we
* attempt to make use of direct access hints provided by the PCI BIOS).
*
* This should be close to trivial, but it isn't, because there are buggy
* chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
*/
static int __init pci_sanity_check(struct pci_raw_ops *o)
{
u32 x = 0;
int devfn;
 
if (pci_probe & PCI_NO_CHECKS)
return 1;
 
for (devfn = 0; devfn < 0x100; devfn++) {
if (o->read(0, 0, devfn, PCI_CLASS_DEVICE, 2, &x))
continue;
if (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)
return 1;
 
if (o->read(0, 0, devfn, PCI_VENDOR_ID, 2, &x))
continue;
if (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ)
return 1;
}
 
DBG("PCI: Sanity check failed\n");
return 0;
}
 
static int __init pci_check_type1(void)
{
unsigned long flags;
unsigned int tmp;
int works = 0;
 
local_irq_save(flags);
 
outb(0x01, 0xCFB);
tmp = inl(0xCF8);
outl(0x80000000, 0xCF8);
if (inl(0xCF8) == 0x80000000 && pci_sanity_check(&pci_direct_conf1)) {
works = 1;
}
outl(tmp, 0xCF8);
local_irq_restore(flags);
 
return works;
}
 
static int __init pci_check_type2(void)
{
unsigned long flags;
int works = 0;
 
local_irq_save(flags);
 
outb(0x00, 0xCFB);
outb(0x00, 0xCF8);
outb(0x00, 0xCFA);
if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00 &&
pci_sanity_check(&pci_direct_conf2)) {
works = 1;
}
 
local_irq_restore(flags);
 
return works;
}
 
static int __init pci_direct_init(void)
{
struct resource *region, *region2;
 
if ((pci_probe & PCI_PROBE_CONF1) == 0)
goto type2;
region = request_region(0xCF8, 8, "PCI conf1");
if (!region)
goto type2;
 
if (pci_check_type1()) {
printk(KERN_INFO "PCI: Using configuration type 1\n");
raw_pci_ops = &pci_direct_conf1;
return 0;
}
release_resource(region);
 
type2:
if ((!pci_probe & PCI_PROBE_CONF2) == 0)
goto out;
region = request_region(0xCF8, 4, "PCI conf2");
if (!region)
goto out;
region2 = request_region(0xC000, 0x1000, "PCI conf2");
if (!region2)
goto fail2;
 
if (pci_check_type2()) {
printk(KERN_INFO "PCI: Using configuration type 2\n");
raw_pci_ops = &pci_direct_conf2;
return 0;
}
 
release_resource(region2);
fail2:
release_resource(region);
 
out:
return 0;
}
 
arch_initcall(pci_direct_init);
/shark/trunk/drivers/newpci/pci.c
1,5 → 1,5
/*
* $Id: pci.c,v 1.2 2004-01-29 09:20:41 giacomo Exp $
* $Id: pci.c,v 1.3 2004-01-29 13:23:34 giacomo Exp $
*
* PCI Bus Services, see include/linux/pci.h for further explanation.
*
716,7 → 716,7
return 0;
}
static int __devinit pci_init(void)
int __devinit pci_init(void)
{
struct pci_dev *dev = NULL;
 
/shark/trunk/drivers/newpci/pcbios.c
0,0 → 1,485
/*
* BIOS32 and PCI BIOS handling.
*/
 
#include <linuxcomp.h>
 
#include <linux/pci.h>
#include <linux/init.h>
#include "pci2.h"
#include "pci-functions.h"
 
 
/* BIOS32 signature: "_32_" */
#define BIOS32_SIGNATURE (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24))
 
/* PCI signature: "PCI " */
#define PCI_SIGNATURE (('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24))
 
/* PCI service signature: "$PCI" */
#define PCI_SERVICE (('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24))
 
/* PCI BIOS hardware mechanism flags */
#define PCIBIOS_HW_TYPE1 0x01
#define PCIBIOS_HW_TYPE2 0x02
#define PCIBIOS_HW_TYPE1_SPEC 0x10
#define PCIBIOS_HW_TYPE2_SPEC 0x20
 
/*
* This is the standard structure used to identify the entry point
* to the BIOS32 Service Directory, as documented in
* Standard BIOS 32-bit Service Directory Proposal
* Revision 0.4 May 24, 1993
* Phoenix Technologies Ltd.
* Norwood, MA
* and the PCI BIOS specification.
*/
 
union bios32 {
struct {
unsigned long signature; /* _32_ */
unsigned long entry; /* 32 bit physical address */
unsigned char revision; /* Revision level, 0 */
unsigned char length; /* Length in paragraphs should be 01 */
unsigned char checksum; /* All bytes must add up to zero */
unsigned char reserved[5]; /* Must be zero */
} fields;
char chars[16];
};
 
/*
* Physical address of the service directory. I don't know if we're
* allowed to have more than one of these or not, so just in case
* we'll make pcibios_present() take a memory start parameter and store
* the array there.
*/
 
static struct {
unsigned long address;
unsigned short segment;
} bios32_indirect = { 0, __KERNEL_CS };
 
/*
* Returns the entry point for the given service, NULL on error
*/
 
static unsigned long bios32_service(unsigned long service)
{
unsigned char return_code; /* %al */
unsigned long address; /* %ebx */
unsigned long length; /* %ecx */
unsigned long entry; /* %edx */
unsigned long flags;
 
local_irq_save(flags);
__asm__("lcall *(%%edi); cld"
: "=a" (return_code),
"=b" (address),
"=c" (length),
"=d" (entry)
: "0" (service),
"1" (0),
"D" (&bios32_indirect));
local_irq_restore(flags);
 
switch (return_code) {
case 0:
return address + entry;
case 0x80: /* Not present */
printk(KERN_WARNING "bios32_service(0x%lx): not present\n", service);
return 0;
default: /* Shouldn't happen */
printk(KERN_WARNING "bios32_service(0x%lx): returned 0x%x -- BIOS bug!\n",
service, return_code);
return 0;
}
}
 
static struct {
unsigned long address;
unsigned short segment;
} pci_indirect = { 0, __KERNEL_CS };
 
static int pci_bios_present;
 
static int __devinit check_pcibios(void)
{
u32 signature, eax, ebx, ecx;
u8 status, major_ver, minor_ver, hw_mech;
unsigned long flags, pcibios_entry;
 
if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
pci_indirect.address = pcibios_entry + PAGE_OFFSET;
 
local_irq_save(flags);
__asm__(
"lcall *(%%edi); cld\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=d" (signature),
"=a" (eax),
"=b" (ebx),
"=c" (ecx)
: "1" (PCIBIOS_PCI_BIOS_PRESENT),
"D" (&pci_indirect)
: "memory");
local_irq_restore(flags);
 
status = (eax >> 8) & 0xff;
hw_mech = eax & 0xff;
major_ver = (ebx >> 8) & 0xff;
minor_ver = ebx & 0xff;
if (pcibios_last_bus < 0)
pcibios_last_bus = ecx & 0xff;
DBG("PCI: BIOS probe returned s=%02x hw=%02x ver=%02x.%02x l=%02x\n",
status, hw_mech, major_ver, minor_ver, pcibios_last_bus);
if (status || signature != PCI_SIGNATURE) {
printk (KERN_ERR "PCI: BIOS BUG #%x[%08x] found\n",
status, signature);
return 0;
}
printk(KERN_INFO "PCI: PCI BIOS revision %x.%02x entry at 0x%lx, last bus=%d\n",
major_ver, minor_ver, pcibios_entry, pcibios_last_bus);
#ifdef CONFIG_PCI_DIRECT
if (!(hw_mech & PCIBIOS_HW_TYPE1))
pci_probe &= ~PCI_PROBE_CONF1;
if (!(hw_mech & PCIBIOS_HW_TYPE2))
pci_probe &= ~PCI_PROBE_CONF2;
#endif
return 1;
}
return 0;
}
 
static int __devinit pci_bios_find_device (unsigned short vendor, unsigned short device_id,
unsigned short index, unsigned char *bus, unsigned char *device_fn)
{
unsigned short bx;
unsigned short ret;
 
__asm__("lcall *(%%edi); cld\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=b" (bx),
"=a" (ret)
: "1" (PCIBIOS_FIND_PCI_DEVICE),
"c" (device_id),
"d" (vendor),
"S" ((int) index),
"D" (&pci_indirect));
*bus = (bx >> 8) & 0xff;
*device_fn = bx & 0xff;
return (int) (ret & 0xff00) >> 8;
}
 
static int pci_bios_read (int seg, int bus, int devfn, int reg, int len, u32 *value)
{
unsigned long result = 0;
unsigned long flags;
unsigned long bx = (bus << 8) | devfn;
 
if (!value || (bus > 255) || (devfn > 255) || (reg > 255))
return -EINVAL;
 
spin_lock_irqsave(&pci_config_lock, flags);
 
switch (len) {
case 1:
__asm__("lcall *(%%esi); cld\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=c" (*value),
"=a" (result)
: "1" (PCIBIOS_READ_CONFIG_BYTE),
"b" (bx),
"D" ((long)reg),
"S" (&pci_indirect));
break;
case 2:
__asm__("lcall *(%%esi); cld\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=c" (*value),
"=a" (result)
: "1" (PCIBIOS_READ_CONFIG_WORD),
"b" (bx),
"D" ((long)reg),
"S" (&pci_indirect));
break;
case 4:
__asm__("lcall *(%%esi); cld\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=c" (*value),
"=a" (result)
: "1" (PCIBIOS_READ_CONFIG_DWORD),
"b" (bx),
"D" ((long)reg),
"S" (&pci_indirect));
break;
}
 
spin_unlock_irqrestore(&pci_config_lock, flags);
 
return (int)((result & 0xff00) >> 8);
}
 
static int pci_bios_write (int seg, int bus, int devfn, int reg, int len, u32 value)
{
unsigned long result = 0;
unsigned long flags;
unsigned long bx = (bus << 8) | devfn;
 
if ((bus > 255) || (devfn > 255) || (reg > 255))
return -EINVAL;
 
spin_lock_irqsave(&pci_config_lock, flags);
 
switch (len) {
case 1:
__asm__("lcall *(%%esi); cld\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=a" (result)
: "0" (PCIBIOS_WRITE_CONFIG_BYTE),
"c" (value),
"b" (bx),
"D" ((long)reg),
"S" (&pci_indirect));
break;
case 2:
__asm__("lcall *(%%esi); cld\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=a" (result)
: "0" (PCIBIOS_WRITE_CONFIG_WORD),
"c" (value),
"b" (bx),
"D" ((long)reg),
"S" (&pci_indirect));
break;
case 4:
__asm__("lcall *(%%esi); cld\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=a" (result)
: "0" (PCIBIOS_WRITE_CONFIG_DWORD),
"c" (value),
"b" (bx),
"D" ((long)reg),
"S" (&pci_indirect));
break;
}
 
spin_unlock_irqrestore(&pci_config_lock, flags);
 
return (int)((result & 0xff00) >> 8);
}
 
 
/*
* Function table for BIOS32 access
*/
 
static struct pci_raw_ops pci_bios_access = {
.read = pci_bios_read,
.write = pci_bios_write
};
 
/*
* Try to find PCI BIOS.
*/
 
static struct pci_raw_ops * __devinit pci_find_bios(void)
{
union bios32 *check;
unsigned char sum;
int i, length;
 
/*
* Follow the standard procedure for locating the BIOS32 Service
* directory by scanning the permissible address range from
* 0xe0000 through 0xfffff for a valid BIOS32 structure.
*/
 
for (check = (union bios32 *) __va(0xe0000);
check <= (union bios32 *) __va(0xffff0);
++check) {
if (check->fields.signature != BIOS32_SIGNATURE)
continue;
length = check->fields.length * 16;
if (!length)
continue;
sum = 0;
for (i = 0; i < length ; ++i)
sum += check->chars[i];
if (sum != 0)
continue;
if (check->fields.revision != 0) {
printk("PCI: unsupported BIOS32 revision %d at 0x%p\n",
check->fields.revision, check);
continue;
}
DBG("PCI: BIOS32 Service Directory structure at 0x%p\n", check);
if (check->fields.entry >= 0x100000) {
printk("PCI: BIOS32 entry (0x%p) in high memory, cannot use.\n", check);
return NULL;
} else {
unsigned long bios32_entry = check->fields.entry;
DBG("PCI: BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
bios32_indirect.address = bios32_entry + PAGE_OFFSET;
if (check_pcibios())
return &pci_bios_access;
}
break; /* Hopefully more than one BIOS32 cannot happen... */
}
 
return NULL;
}
 
/*
* Sort the device list according to PCI BIOS. Nasty hack, but since some
* fool forgot to define the `correct' device order in the PCI BIOS specs
* and we want to be (possibly bug-to-bug ;-]) compatible with older kernels
* which used BIOS ordering, we are bound to do this...
*/
 
void __devinit pcibios_sort(void)
{
LIST_HEAD(sorted_devices);
struct list_head *ln;
struct pci_dev *dev, *d;
int idx, found;
unsigned char bus, devfn;
 
DBG("PCI: Sorting device list...\n");
while (!list_empty(&pci_devices)) {
ln = pci_devices.next;
dev = pci_dev_g(ln);
idx = found = 0;
while (pci_bios_find_device(dev->vendor, dev->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) {
idx++;
for (ln=pci_devices.next; ln != &pci_devices; ln=ln->next) {
d = pci_dev_g(ln);
if (d->bus->number == bus && d->devfn == devfn) {
list_del(&d->global_list);
list_add_tail(&d->global_list, &sorted_devices);
if (d == dev)
found = 1;
break;
}
}
if (ln == &pci_devices) {
printk(KERN_WARNING "PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn);
/*
* We must not continue scanning as several buggy BIOSes
* return garbage after the last device. Grr.
*/
break;
}
}
if (!found) {
printk(KERN_WARNING "PCI: Device %02x:%02x not found by BIOS\n",
dev->bus->number, dev->devfn);
list_del(&dev->global_list);
list_add_tail(&dev->global_list, &sorted_devices);
}
}
list_splice(&sorted_devices, &pci_devices);
}
 
/*
* BIOS Functions for IRQ Routing
*/
 
struct irq_routing_options {
u16 size;
struct irq_info *table;
u16 segment;
} __attribute__((packed));
 
struct irq_routing_table * __devinit pcibios_get_irq_routing_table(void)
{
struct irq_routing_options opt;
struct irq_routing_table *rt = NULL;
int ret, map;
unsigned long page;
 
if (!pci_bios_present)
return NULL;
page = __get_free_page(GFP_KERNEL);
if (!page)
return NULL;
opt.table = (struct irq_info *) page;
opt.size = PAGE_SIZE;
opt.segment = __KERNEL_DS;
 
DBG("PCI: Fetching IRQ routing table... ");
__asm__("push %%es\n\t"
"push %%ds\n\t"
"pop %%es\n\t"
"lcall *(%%esi); cld\n\t"
"pop %%es\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=a" (ret),
"=b" (map),
"+m" (opt)
: "0" (PCIBIOS_GET_ROUTING_OPTIONS),
"1" (0),
"D" ((long) &opt),
"S" (&pci_indirect));
DBG("OK ret=%d, size=%d, map=%x\n", ret, opt.size, map);
if (ret & 0xff00)
printk(KERN_ERR "PCI: Error %02x when fetching IRQ routing table.\n", (ret >> 8) & 0xff);
else if (opt.size) {
rt = kmalloc(sizeof(struct irq_routing_table) + opt.size, GFP_KERNEL);
if (rt) {
memset(rt, 0, sizeof(struct irq_routing_table));
rt->size = opt.size + sizeof(struct irq_routing_table);
rt->exclusive_irqs = map;
memcpy(rt->slots, (void *) page, opt.size);
printk(KERN_INFO "PCI: Using BIOS Interrupt Routing Table\n");
}
}
free_page(page);
return rt;
}
 
 
int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq)
{
int ret;
 
__asm__("lcall *(%%esi); cld\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=a" (ret)
: "0" (PCIBIOS_SET_PCI_HW_INT),
"b" ((dev->bus->number << 8) | dev->devfn),
"c" ((irq << 8) | (pin + 10)),
"S" (&pci_indirect));
return !(ret & 0xff00);
}
 
static int __init pci_pcbios_init(void)
{
if ((pci_probe & PCI_PROBE_BIOS)
&& ((raw_pci_ops = pci_find_bios()))) {
pci_probe |= PCI_BIOS_SORT;
pci_bios_present = 1;
}
return 0;
}
 
arch_initcall(pci_pcbios_init);
/shark/trunk/drivers/newpci/common.c
0,0 → 1,243
/*
* Low-Level PCI Support for PC
*
* (c) 1999--2000 Martin Mares <mj@ucw.cz>
*/
 
#include <linuxcomp.h>
 
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/ioport.h>
#include <linux/init.h>
 
#include <asm/segment.h>
#include <asm/io.h>
#include <asm/smp.h>
 
#include "pci2.h"
 
#ifdef CONFIG_PCI_BIOS
extern void pcibios_sort(void);
#endif
 
unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2;
 
int pcibios_last_bus = -1;
struct pci_bus *pci_root_bus = NULL;
struct pci_raw_ops *raw_pci_ops;
 
static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
{
return raw_pci_ops->read(0, bus->number, devfn, where, size, value);
}
 
static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
{
return raw_pci_ops->write(0, bus->number, devfn, where, size, value);
}
 
struct pci_ops pci_root_ops = {
.read = pci_read,
.write = pci_write,
};
 
/*
* legacy, numa, and acpi all want to call pcibios_scan_root
* from their initcalls. This flag prevents that.
*/
int pcibios_scanned;
 
/*
* This interrupt-safe spinlock protects all accesses to PCI
* configuration space.
*/
spinlock_t pci_config_lock = SPIN_LOCK_UNLOCKED;
 
/*
* Several buggy motherboards address only 16 devices and mirror
* them to next 16 IDs. We try to detect this `feature' on all
* primary buses (those containing host bridges as they are
* expected to be unique) and remove the ghost devices.
*/
 
static void __devinit pcibios_fixup_ghosts(struct pci_bus *b)
{
struct list_head *ln, *mn;
struct pci_dev *d, *e;
int mirror = PCI_DEVFN(16,0);
int seen_host_bridge = 0;
int i;
 
DBG("PCI: Scanning for ghost devices on bus %d\n", b->number);
for (ln=b->devices.next; ln != &b->devices; ln=ln->next) {
d = pci_dev_b(ln);
if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST)
seen_host_bridge++;
for (mn=ln->next; mn != &b->devices; mn=mn->next) {
e = pci_dev_b(mn);
if (e->devfn != d->devfn + mirror ||
e->vendor != d->vendor ||
e->device != d->device ||
e->class != d->class)
continue;
for(i=0; i<PCI_NUM_RESOURCES; i++)
if (e->resource[i].start != d->resource[i].start ||
e->resource[i].end != d->resource[i].end ||
e->resource[i].flags != d->resource[i].flags)
continue;
break;
}
if (mn == &b->devices)
return;
}
if (!seen_host_bridge)
return;
printk(KERN_WARNING "PCI: Ignoring ghost devices on bus %02x\n", b->number);
 
ln = &b->devices;
while (ln->next != &b->devices) {
d = pci_dev_b(ln->next);
if (d->devfn >= mirror) {
list_del(&d->global_list);
list_del(&d->bus_list);
kfree(d);
} else
ln = ln->next;
}
}
 
/*
* Called after each bus is probed, but before its children
* are examined.
*/
 
void __devinit pcibios_fixup_bus(struct pci_bus *b)
{
pcibios_fixup_ghosts(b);
pci_read_bridge_bases(b);
}
 
 
struct pci_bus * __devinit pcibios_scan_root(int busnum)
{
struct pci_bus *bus = NULL;
 
while ((bus = pci_find_next_bus(bus)) != NULL) {
if (bus->number == busnum) {
/* Already scanned */
return bus;
}
}
 
printk("PCI: Probing PCI hardware (bus %02x)\n", busnum);
 
return pci_scan_bus(busnum, &pci_root_ops, NULL);
}
 
extern u8 pci_cache_line_size;
 
static int __init pcibios_init(void)
{
struct cpuinfo_x86 *c = &boot_cpu_data;
 
if (!raw_pci_ops) {
printk("PCI: System does not support PCI\n");
return 0;
}
 
/*
* Assume PCI cacheline size of 32 bytes for all x86s except K7/K8
* and P4. It's also good for 386/486s (which actually have 16)
* as quite a few PCI devices do not support smaller values.
*/
pci_cache_line_size = 32 >> 2;
if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD)
pci_cache_line_size = 64 >> 2; /* K7 & K8 */
else if (c->x86 > 6 && c->x86_vendor == X86_VENDOR_INTEL)
pci_cache_line_size = 128 >> 2; /* P4 */
 
pcibios_resource_survey();
 
#ifdef CONFIG_PCI_BIOS
if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT))
pcibios_sort();
#endif
return 0;
}
 
subsys_initcall(pcibios_init);
 
char * __devinit pcibios_setup(char *str)
{
if (!strcmp(str, "off")) {
pci_probe = 0;
return NULL;
}
#ifdef CONFIG_PCI_BIOS
else if (!strcmp(str, "bios")) {
pci_probe = PCI_PROBE_BIOS;
return NULL;
} else if (!strcmp(str, "nobios")) {
pci_probe &= ~PCI_PROBE_BIOS;
return NULL;
} else if (!strcmp(str, "nosort")) {
pci_probe |= PCI_NO_SORT;
return NULL;
} else if (!strcmp(str, "biosirq")) {
pci_probe |= PCI_BIOS_IRQ_SCAN;
return NULL;
}
#endif
#ifdef CONFIG_PCI_DIRECT
else if (!strcmp(str, "conf1")) {
pci_probe = PCI_PROBE_CONF1 | PCI_NO_CHECKS;
return NULL;
}
else if (!strcmp(str, "conf2")) {
pci_probe = PCI_PROBE_CONF2 | PCI_NO_CHECKS;
return NULL;
}
#endif
#ifdef CONFIG_ACPI_PCI
else if (!strcmp(str, "noacpi")) {
pci_probe |= PCI_NO_ACPI_ROUTING;
return NULL;
}
#endif
#ifndef CONFIG_X86_VISWS
else if (!strcmp(str, "usepirqmask")) {
pci_probe |= PCI_USE_PIRQ_MASK;
return NULL;
} else if (!strncmp(str, "irqmask=", 8)) {
pcibios_irq_mask = simple_strtol(str+8, NULL, 0);
return NULL;
} else if (!strncmp(str, "lastbus=", 8)) {
pcibios_last_bus = simple_strtol(str+8, NULL, 0);
return NULL;
}
#endif
else if (!strcmp(str, "rom")) {
pci_probe |= PCI_ASSIGN_ROMS;
return NULL;
} else if (!strcmp(str, "assign-busses")) {
pci_probe |= PCI_ASSIGN_ALL_BUSSES;
return NULL;
}
return str;
}
 
unsigned int pcibios_assign_all_busses(void)
{
return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;
}
 
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
int err;
 
if ((err = pcibios_enable_resources(dev, mask)) < 0)
return err;
 
return pcibios_enable_irq(dev);
}
/shark/trunk/drivers/newpci/i386.c
0,0 → 1,302
/*
* Low-Level PCI Access for i386 machines
*
* Copyright 1993, 1994 Drew Eckhardt
* Visionary Computing
* (Unix and Linux consulting and custom programming)
* Drew@Colorado.EDU
* +1 (303) 786-7975
*
* Drew's work was sponsored by:
* iX Multiuser Multitasking Magazine
* Hannover, Germany
* hm@ix.de
*
* Copyright 1997--2000 Martin Mares <mj@ucw.cz>
*
* For more information, please consult the following manuals (look at
* http://www.pcisig.com/ for how to get them):
*
* PCI BIOS Specification
* PCI Local Bus Specification
* PCI to PCI Bridge Specification
* PCI System Design Guide
*
*/
 
#include <linuxcomp.h>
 
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/errno.h>
 
#include "pci2.h"
 
/*
* We need to avoid collisions with `mirrored' VGA ports
* and other strange ISA hardware, so we always want the
* addresses to be allocated in the 0x000-0x0ff region
* modulo 0x400.
*
* Why? Because some silly external IO cards only decode
* the low 10 bits of the IO address. The 0x00-0xff region
* is reserved for motherboard devices that decode all 16
* bits, so it's ok to allocate at, say, 0x2800-0x28ff,
* but we want to try to avoid allocating at 0x2900-0x2bff
* which might have be mirrored at 0x0100-0x03ff..
*/
void
pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{
if (res->flags & IORESOURCE_IO) {
unsigned long start = res->start;
 
if (start & 0x300) {
start = (start + 0x3ff) & ~0x3ff;
res->start = start;
}
}
}
 
 
/*
* Handle resources of PCI devices. If the world were perfect, we could
* just allocate all the resource regions and do nothing more. It isn't.
* On the other hand, we cannot just re-allocate all devices, as it would
* require us to know lots of host bridge internals. So we attempt to
* keep as much of the original configuration as possible, but tweak it
* when it's found to be wrong.
*
* Known BIOS problems we have to work around:
* - I/O or memory regions not configured
* - regions configured, but not enabled in the command register
* - bogus I/O addresses above 64K used
* - expansion ROMs left enabled (this may sound harmless, but given
* the fact the PCI specs explicitly allow address decoders to be
* shared between expansion ROMs and other resource regions, it's
* at least dangerous)
*
* Our solution:
* (1) Allocate resources for all buses behind PCI-to-PCI bridges.
* This gives us fixed barriers on where we can allocate.
* (2) Allocate resources for all enabled devices. If there is
* a collision, just mark the resource as unallocated. Also
* disable expansion ROMs during this step.
* (3) Try to allocate resources for disabled devices. If the
* resources were assigned correctly, everything goes well,
* if they weren't, they won't disturb allocation of other
* resources.
* (4) Assign new addresses to resources which were either
* not configured at all or misconfigured. If explicitly
* requested by the user, configure expansion ROM address
* as well.
*/
 
static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
{
struct list_head *ln;
struct pci_bus *bus;
struct pci_dev *dev;
int idx;
struct resource *r, *pr;
 
/* Depth-First Search on bus tree */
for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
bus = pci_bus_b(ln);
if ((dev = bus->self)) {
for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
r = &dev->resource[idx];
if (!r->start)
continue;
pr = pci_find_parent_resource(dev, r);
if (!pr || request_resource(pr, r) < 0)
printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, pci_name(dev));
}
}
pcibios_allocate_bus_resources(&bus->children);
}
}
 
static void __init pcibios_allocate_resources(int pass)
{
struct pci_dev *dev = NULL;
int idx, disabled;
u16 command;
struct resource *r, *pr;
 
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
pci_read_config_word(dev, PCI_COMMAND, &command);
for(idx = 0; idx < 6; idx++) {
r = &dev->resource[idx];
if (r->parent) /* Already allocated */
continue;
if (!r->start) /* Address not assigned at all */
continue;
if (r->flags & IORESOURCE_IO)
disabled = !(command & PCI_COMMAND_IO);
else
disabled = !(command & PCI_COMMAND_MEMORY);
if (pass == disabled) {
DBG("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n",
r->start, r->end, r->flags, disabled, pass);
pr = pci_find_parent_resource(dev, r);
if (!pr || request_resource(pr, r) < 0) {
printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, pci_name(dev));
/* We'll assign a new address later */
r->end -= r->start;
r->start = 0;
}
}
}
if (!pass) {
r = &dev->resource[PCI_ROM_RESOURCE];
if (r->flags & PCI_ROM_ADDRESS_ENABLE) {
/* Turn the ROM off, leave the resource region, but keep it unregistered. */
u32 reg;
DBG("PCI: Switching off ROM of %s\n", pci_name(dev));
r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
pci_read_config_dword(dev, dev->rom_base_reg, &reg);
pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE);
}
}
}
}
 
static void __init pcibios_assign_resources(void)
{
struct pci_dev *dev = NULL;
int idx;
struct resource *r;
 
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
int class = dev->class >> 8;
 
/* Don't touch classless devices and host bridges */
if (!class || class == PCI_CLASS_BRIDGE_HOST)
continue;
 
for(idx=0; idx<6; idx++) {
r = &dev->resource[idx];
 
/*
* Don't touch IDE controllers and I/O ports of video cards!
*/
if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) ||
(class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
continue;
 
/*
* We shall assign a new address to this resource, either because
* the BIOS forgot to do so or because we have decided the old
* address was unusable for some reason.
*/
if (!r->start && r->end)
pci_assign_resource(dev, idx);
}
 
if (pci_probe & PCI_ASSIGN_ROMS) {
r = &dev->resource[PCI_ROM_RESOURCE];
r->end -= r->start;
r->start = 0;
if (r->end)
pci_assign_resource(dev, PCI_ROM_RESOURCE);
}
}
}
 
void __init pcibios_resource_survey(void)
{
DBG("PCI: Allocating resources\n");
pcibios_allocate_bus_resources(&pci_root_buses);
pcibios_allocate_resources(0);
pcibios_allocate_resources(1);
pcibios_assign_resources();
}
 
int pcibios_enable_resources(struct pci_dev *dev, int mask)
{
u16 cmd, old_cmd;
int idx;
struct resource *r;
 
pci_read_config_word(dev, PCI_COMMAND, &cmd);
old_cmd = cmd;
for(idx=0; idx<6; idx++) {
/* Only set up the requested stuff */
if (!(mask & (1<<idx)))
continue;
 
r = &dev->resource[idx];
if (!r->start && r->end) {
printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", pci_name(dev));
return -EINVAL;
}
if (r->flags & IORESOURCE_IO)
cmd |= PCI_COMMAND_IO;
if (r->flags & IORESOURCE_MEM)
cmd |= PCI_COMMAND_MEMORY;
}
if (dev->resource[PCI_ROM_RESOURCE].start)
cmd |= PCI_COMMAND_MEMORY;
if (cmd != old_cmd) {
printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd);
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
return 0;
}
 
/*
* If we set up a device for bus mastering, we need to check the latency
* timer as certain crappy BIOSes forget to set it properly.
*/
unsigned int pcibios_max_latency = 255;
 
void pcibios_set_master(struct pci_dev *dev)
{
u8 lat;
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
if (lat < 16)
lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
else if (lat > pcibios_max_latency)
lat = pcibios_max_latency;
else
return;
printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat);
pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
}
 
int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine)
{
unsigned long prot;
 
/* I/O space cannot be accessed via normal processor loads and
* stores on this platform.
*/
if (mmap_state == pci_mmap_io)
return -EINVAL;
 
/* Leave vm_pgoff as-is, the PCI space address is the physical
* address on this platform.
*/
vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO);
 
prot = pgprot_val(vma->vm_page_prot);
if (boot_cpu_data.x86 > 3)
prot |= _PAGE_PCD | _PAGE_PWT;
vma->vm_page_prot = __pgprot(prot);
 
/* Write-combine setting is ignored, it is changed via the mtrr
* interfaces on this platform.
*/
if (remap_page_range(vma, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
vma->vm_end - vma->vm_start,
vma->vm_page_prot))
return -EAGAIN;
 
return 0;
}
/shark/trunk/drivers/newpci/irq.c
0,0 → 1,969
/*
* Low-Level PCI Support for PC -- Routing of Interrupts
*
* (c) 1999--2000 Martin Mares <mj@ucw.cz>
*/
 
#include <linuxcomp.h>
 
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <asm/io.h>
#include <asm/smp.h>
#include <asm/io_apic.h>
 
#include "pci2.h"
 
#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
#define PIRQ_VERSION 0x0100
 
int broken_hp_bios_irq9;
 
static struct irq_routing_table *pirq_table;
 
/*
* 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);
};
 
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) = 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;
int i;
u8 sum;
 
for(addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) {
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))
continue;
sum = 0;
for(i=0; i<rt->size; i++)
sum += addr[i];
if (!sum) {
DBG("PCI: Interrupt Routing Table found at 0x%p\n", 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("%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;
if (pci_scan_bus(i, &pci_root_ops, NULL))
printk(KERN_INFO "PCI: Discovered primary peer bus %02x [IRQ]\n", i);
}
pcibios_last_bus = -1;
}
 
/*
* Code for querying and setting of IRQ routes on various interrupt routers.
*/
 
void eisa_set_level_irq(unsigned int irq)
{
unsigned char mask = 1 << (irq & 7);
unsigned int port = 0x4d0 + (irq >> 3);
unsigned char val = inb(port);
 
if (!(val & mask)) {
DBG(" -> edge");
outb(val | mask, port);
}
}
 
/*
* Common IRQ routing practice: nybbles in config space,
* offset by some magic constant.
*/
static unsigned int read_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr)
{
u8 x;
unsigned reg = offset + (nr >> 1);
 
pci_read_config_byte(router, reg, &x);
return (nr & 1) ? (x >> 4) : (x & 0xf);
}
 
static void write_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr, unsigned int val)
{
u8 x;
unsigned reg = offset + (nr >> 1);
 
pci_read_config_byte(router, reg, &x);
x = (nr & 1) ? ((x & 0x0f) | (val << 4)) : ((x & 0xf0) | val);
pci_write_config_byte(router, reg, x);
}
 
/*
* ALI pirq entries are damn ugly, and completely undocumented.
* This has been figured out from pirq tables, and it's not a pretty
* picture.
*/
static int pirq_ali_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
{
static unsigned char irqmap[16] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 };
 
return irqmap[read_config_nybble(router, 0x48, pirq-1)];
}
 
static int pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
{
static unsigned char irqmap[16] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 };
unsigned int val = irqmap[irq];
if (val) {
write_config_nybble(router, 0x48, pirq-1, val);
return 1;
}
return 0;
}
 
/*
* The Intel PIIX4 pirq rules are fairly simple: "pirq" is
* just a pointer to the config space.
*/
static int pirq_piix_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
{
u8 x;
 
pci_read_config_byte(router, pirq, &x);
return (x < 16) ? x : 0;
}
 
static int pirq_piix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
{
pci_write_config_byte(router, pirq, irq);
return 1;
}
 
/*
* The VIA pirq rules are nibble-based, like ALI,
* but without the ugly irq number munging.
* However, PIRQD is in the upper instead of lower 4 bits.
*/
static int pirq_via_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
{
return read_config_nybble(router, 0x55, pirq == 4 ? 5 : pirq);
}
 
static int pirq_via_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
{
write_config_nybble(router, 0x55, pirq == 4 ? 5 : pirq, irq);
return 1;
}
 
/*
* ITE 8330G pirq rules are nibble-based
* FIXME: pirqmap may be { 1, 0, 3, 2 },
* 2+3 are both mapped to irq 9 on my system
*/
static int pirq_ite_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
{
static unsigned char pirqmap[4] = { 1, 0, 2, 3 };
return read_config_nybble(router,0x43, pirqmap[pirq-1]);
}
 
static int pirq_ite_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
{
static unsigned char pirqmap[4] = { 1, 0, 2, 3 };
write_config_nybble(router, 0x43, pirqmap[pirq-1], irq);
return 1;
}
 
/*
* OPTI: high four bits are nibble pointer..
* I wonder what the low bits do?
*/
static int pirq_opti_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
{
return read_config_nybble(router, 0xb8, pirq >> 4);
}
 
static int pirq_opti_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
{
write_config_nybble(router, 0xb8, pirq >> 4, irq);
return 1;
}
 
/*
* Cyrix: nibble offset 0x5C
* 0x5C bits 7:4 is INTB bits 3:0 is INTA
* 0x5D bits 7:4 is INTD bits 3:0 is INTC
*/
static int pirq_cyrix_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
{
return read_config_nybble(router, 0x5C, (pirq-1)^1);
}
 
static int pirq_cyrix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
{
write_config_nybble(router, 0x5C, (pirq-1)^1, irq);
return 1;
}
 
/*
* PIRQ routing for SiS 85C503 router used in several SiS chipsets.
* We have to deal with the following issues here:
* - vendors have different ideas about the meaning of link values
* - some onboard devices (integrated in the chipset) have special
* links and are thus routed differently (i.e. not via PCI INTA-INTD)
* - different revision of the router have a different layout for
* the routing registers, particularly for the onchip devices
*
* For all routing registers the common thing is we have one byte
* per routeable link which is defined as:
* bit 7 IRQ mapping enabled (0) or disabled (1)
* bits [6:4] reserved (sometimes used for onchip devices)
* bits [3:0] IRQ to map to
* allowed: 3-7, 9-12, 14-15
* reserved: 0, 1, 2, 8, 13
*
* The config-space registers located at 0x41/0x42/0x43/0x44 are
* always used to route the normal PCI INT A/B/C/D respectively.
* Apparently there are systems implementing PCI routing table using
* link values 0x01-0x04 and others using 0x41-0x44 for PCI INTA..D.
* We try our best to handle both link mappings.
*
* Currently (2003-05-21) it appears most SiS chipsets follow the
* definition of routing registers from the SiS-5595 southbridge.
* According to the SiS 5595 datasheets the revision id's of the
* router (ISA-bridge) should be 0x01 or 0xb0.
*
* Furthermore we've also seen lspci dumps with revision 0x00 and 0xb1.
* Looks like these are used in a number of SiS 5xx/6xx/7xx chipsets.
* They seem to work with the current routing code. However there is
* some concern because of the two USB-OHCI HCs (original SiS 5595
* had only one). YMMV.
*
* Onchip routing for router rev-id 0x01/0xb0 and probably 0x00/0xb1:
*
* 0x61: IDEIRQ:
* bits [6:5] must be written 01
* bit 4 channel-select primary (0), secondary (1)
*
* 0x62: USBIRQ:
* bit 6 OHCI function disabled (0), enabled (1)
*
* 0x6a: ACPI/SCI IRQ: bits 4-6 reserved
*
* 0x7e: Data Acq. Module IRQ - bits 4-6 reserved
*
* We support USBIRQ (in addition to INTA-INTD) and keep the
* IDE, ACPI and DAQ routing untouched as set by the BIOS.
*
* Currently the only reported exception is the new SiS 65x chipset
* which includes the SiS 69x southbridge. Here we have the 85C503
* router revision 0x04 and there are changes in the register layout
* mostly related to the different USB HCs with USB 2.0 support.
*
* Onchip routing for router rev-id 0x04 (try-and-error observation)
*
* 0x60/0x61/0x62/0x63: 1xEHCI and 3xOHCI (companion) USB-HCs
* bit 6-4 are probably unused, not like 5595
*/
 
#define PIRQ_SIS_IRQ_MASK 0x0f
#define PIRQ_SIS_IRQ_DISABLE 0x80
#define PIRQ_SIS_USB_ENABLE 0x40
 
static int pirq_sis_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
{
u8 x;
int reg;
 
reg = pirq;
if (reg >= 0x01 && reg <= 0x04)
reg += 0x40;
pci_read_config_byte(router, reg, &x);
return (x & PIRQ_SIS_IRQ_DISABLE) ? 0 : (x & PIRQ_SIS_IRQ_MASK);
}
 
static int pirq_sis_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
{
u8 x;
int reg;
 
reg = pirq;
if (reg >= 0x01 && reg <= 0x04)
reg += 0x40;
pci_read_config_byte(router, reg, &x);
x &= ~(PIRQ_SIS_IRQ_MASK | PIRQ_SIS_IRQ_DISABLE);
x |= irq ? irq: PIRQ_SIS_IRQ_DISABLE;
pci_write_config_byte(router, reg, x);
return 1;
}
 
 
/*
* VLSI: nibble offset 0x74 - educated guess due to routing table and
* config space of VLSI 82C534 PCI-bridge/router (1004:0102)
* Tested on HP OmniBook 800 covering PIRQ 1, 2, 4, 8 for onboard
* devices, PIRQ 3 for non-pci(!) soundchip and (untested) PIRQ 6
* for the busbridge to the docking station.
*/
 
static int pirq_vlsi_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
{
if (pirq > 8) {
printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq);
return 0;
}
return read_config_nybble(router, 0x74, pirq-1);
}
 
static int pirq_vlsi_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
{
if (pirq > 8) {
printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq);
return 0;
}
write_config_nybble(router, 0x74, pirq-1, irq);
return 1;
}
 
/*
* ServerWorks: PCI interrupts mapped to system IRQ lines through Index
* and Redirect I/O registers (0x0c00 and 0x0c01). The Index register
* format is (PCIIRQ## | 0x10), e.g.: PCIIRQ10=0x1a. The Redirect
* register is a straight binary coding of desired PIC IRQ (low nibble).
*
* The 'link' value in the PIRQ table is already in the correct format
* for the Index register. There are some special index values:
* 0x00 for ACPI (SCI), 0x01 for USB, 0x02 for IDE0, 0x04 for IDE1,
* and 0x03 for SMBus.
*/
static int pirq_serverworks_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
{
outb_p(pirq, 0xc00);
return inb(0xc01) & 0xf;
}
 
static int pirq_serverworks_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
{
outb_p(pirq, 0xc00);
outb_p(irq, 0xc01);
return 1;
}
 
/* Support for AMD756 PCI IRQ Routing
* Jhon H. Caicedo <jhcaiced@osso.org.co>
* Jun/21/2001 0.2.0 Release, fixed to use "nybble" functions... (jhcaiced)
* Jun/19/2001 Alpha Release 0.1.0 (jhcaiced)
* The AMD756 pirq rules are nibble-based
* offset 0x56 0-3 PIRQA 4-7 PIRQB
* offset 0x57 0-3 PIRQC 4-7 PIRQD
*/
static int pirq_amd756_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
{
u8 irq;
irq = 0;
if (pirq <= 4)
{
irq = read_config_nybble(router, 0x56, pirq - 1);
}
printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d get irq : %2d\n",
dev->vendor, dev->device, pirq, irq);
return irq;
}
 
static int pirq_amd756_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
{
printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d SET irq : %2d\n",
dev->vendor, dev->device, pirq, irq);
if (pirq <= 4)
{
write_config_nybble(router, 0x56, pirq - 1, irq);
}
return 1;
}
 
#ifdef CONFIG_PCI_BIOS
 
static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
{
struct pci_dev *bridge;
int pin = pci_get_interrupt_pin(dev, &bridge);
return pcibios_set_irq_routing(bridge, pin, irq);
}
 
#endif
 
 
static __init int intel_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
{
#if 0 /* Let's see what chip this is supposed to be ... */
/* We must not touch 440GX even if we have tables. 440GX has
different IRQ routing weirdness */
if (pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82440GX, NULL))
return 0;
#endif
 
switch(device)
{
case PCI_DEVICE_ID_INTEL_82371FB_0:
case PCI_DEVICE_ID_INTEL_82371SB_0:
case PCI_DEVICE_ID_INTEL_82371AB_0:
case PCI_DEVICE_ID_INTEL_82371MX:
case PCI_DEVICE_ID_INTEL_82443MX_0:
case PCI_DEVICE_ID_INTEL_82801AA_0:
case PCI_DEVICE_ID_INTEL_82801AB_0:
case PCI_DEVICE_ID_INTEL_82801BA_0:
case PCI_DEVICE_ID_INTEL_82801BA_10:
case PCI_DEVICE_ID_INTEL_82801CA_0:
case PCI_DEVICE_ID_INTEL_82801CA_12:
case PCI_DEVICE_ID_INTEL_82801DB_0:
case PCI_DEVICE_ID_INTEL_82801E_0:
case PCI_DEVICE_ID_INTEL_82801EB_0:
case PCI_DEVICE_ID_INTEL_ESB_0:
r->name = "PIIX/ICH";
r->get = pirq_piix_get;
r->set = pirq_piix_set;
return 1;
}
return 0;
}
 
static __init int via_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
{
/* FIXME: We should move some of the quirk fixup stuff here */
switch(device)
{
case PCI_DEVICE_ID_VIA_82C586_0:
case PCI_DEVICE_ID_VIA_82C596:
case PCI_DEVICE_ID_VIA_82C686:
case PCI_DEVICE_ID_VIA_8231:
/* FIXME: add new ones for 8233/5 */
r->name = "VIA";
r->get = pirq_via_get;
r->set = pirq_via_set;
return 1;
}
return 0;
}
 
static __init int vlsi_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
{
switch(device)
{
case PCI_DEVICE_ID_VLSI_82C534:
r->name = "VLSI 82C534";
r->get = pirq_vlsi_get;
r->set = pirq_vlsi_set;
return 1;
}
return 0;
}
 
 
static __init int serverworks_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
{
switch(device)
{
case PCI_DEVICE_ID_SERVERWORKS_OSB4:
case PCI_DEVICE_ID_SERVERWORKS_CSB5:
r->name = "ServerWorks";
r->get = pirq_serverworks_get;
r->set = pirq_serverworks_set;
return 1;
}
return 0;
}
 
static __init int sis_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
{
if (device != PCI_DEVICE_ID_SI_503)
return 0;
r->name = "SIS";
r->get = pirq_sis_get;
r->set = pirq_sis_set;
DBG("PCI: Detecting SiS router at %02x:%02x\n",
rt->rtr_bus, rt->rtr_devfn);
return 1;
}
 
static __init int cyrix_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
{
switch(device)
{
case PCI_DEVICE_ID_CYRIX_5520:
r->name = "NatSemi";
r->get = pirq_cyrix_get;
r->set = pirq_cyrix_set;
return 1;
}
return 0;
}
 
static __init int opti_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
{
switch(device)
{
case PCI_DEVICE_ID_OPTI_82C700:
r->name = "OPTI";
r->get = pirq_opti_get;
r->set = pirq_opti_set;
return 1;
}
return 0;
}
 
static __init int ite_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
{
switch(device)
{
case PCI_DEVICE_ID_ITE_IT8330G_0:
r->name = "ITE";
r->get = pirq_ite_get;
r->set = pirq_ite_set;
return 1;
}
return 0;
}
 
static __init int ali_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
{
switch(device)
{
case PCI_DEVICE_ID_AL_M1533:
r->name = "ALI";
r->get = pirq_ali_get;
r->set = pirq_ali_set;
return 1;
/* Should add 156x some day */
}
return 0;
}
 
static __init int amd_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
{
switch(device)
{
case PCI_DEVICE_ID_AMD_VIPER_740B:
r->name = "AMD756";
break;
case PCI_DEVICE_ID_AMD_VIPER_7413:
r->name = "AMD766";
break;
case PCI_DEVICE_ID_AMD_VIPER_7443:
r->name = "AMD768";
break;
default:
return 0;
}
r->get = pirq_amd756_get;
r->set = pirq_amd756_set;
return 1;
}
static __initdata struct irq_router_handler pirq_routers[] = {
{ PCI_VENDOR_ID_INTEL, intel_router_probe },
{ PCI_VENDOR_ID_AL, ali_router_probe },
{ PCI_VENDOR_ID_ITE, ite_router_probe },
{ PCI_VENDOR_ID_VIA, via_router_probe },
{ PCI_VENDOR_ID_OPTI, opti_router_probe },
{ PCI_VENDOR_ID_SI, sis_router_probe },
{ PCI_VENDOR_ID_CYRIX, cyrix_router_probe },
{ PCI_VENDOR_ID_VLSI, vlsi_router_probe },
{ PCI_VENDOR_ID_SERVERWORKS, serverworks_router_probe },
{ PCI_VENDOR_ID_AMD, amd_router_probe },
/* Someone with docs needs to add the ATI Radeon IGP */
{ 0, NULL }
};
static struct irq_router pirq_router;
static struct pci_dev *pirq_router_dev;
 
 
/*
* FIXME: should we have an option to say "generic for
* chipset" ?
*/
static void __init pirq_find_router(struct irq_router *r)
{
struct irq_routing_table *rt = pirq_table;
struct irq_router_handler *h;
 
#ifdef CONFIG_PCI_BIOS
if (!rt->signature) {
printk(KERN_INFO "PCI: Using BIOS for IRQ routing\n");
r->set = pirq_bios_set;
r->name = "BIOS";
return;
}
#endif
 
/* Default unless a driver reloads it */
r->name = "default";
r->get = NULL;
r->set = NULL;
DBG("PCI: Attempting to find IRQ router for %04x:%04x\n",
rt->rtr_vendor, rt->rtr_device);
 
pirq_router_dev = pci_find_slot(rt->rtr_bus, rt->rtr_devfn);
if (!pirq_router_dev) {
DBG("PCI: Interrupt router not found at %02x:%02x\n", rt->rtr_bus, rt->rtr_devfn);
return;
}
 
for( h = pirq_routers; h->vendor; h++) {
/* First look for a router match */
if (rt->rtr_vendor == h->vendor && h->probe(r, pirq_router_dev, rt->rtr_device))
break;
/* Fall back to a device match */
if (pirq_router_dev->vendor == h->vendor && h->probe(r, pirq_router_dev, pirq_router_dev->device))
break;
}
printk(KERN_INFO "PCI: Using IRQ router %s [%04x/%04x] at %s\n",
pirq_router.name,
pirq_router_dev->vendor,
pirq_router_dev->device,
pci_name(pirq_router_dev));
}
 
static struct irq_info *pirq_get_info(struct pci_dev *dev)
{
struct irq_routing_table *rt = pirq_table;
int entries = (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info);
struct irq_info *info;
 
for (info = rt->slots; entries--; info++)
if (info->bus == dev->bus->number && PCI_SLOT(info->devfn) == PCI_SLOT(dev->devfn))
return info;
return NULL;
}
 
static irqreturn_t pcibios_test_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{
return IRQ_NONE;
}
 
static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
{
u8 pin;
struct irq_info *info;
int i, pirq, newirq;
int irq = 0;
u32 mask;
struct irq_router *r = &pirq_router;
struct pci_dev *dev2 = NULL;
char *msg = NULL;
 
/* Find IRQ pin */
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (!pin) {
DBG(" -> no interrupt pin\n");
return 0;
}
pin = pin - 1;
 
/* Find IRQ routing entry */
 
if (!pirq_table)
return 0;
DBG("IRQ for %s:%d", pci_name(dev), pin);
info = pirq_get_info(dev);
if (!info) {
DBG(" -> not found in routing table\n");
return 0;
}
pirq = info->irq[pin].link;
mask = info->irq[pin].bitmap;
if (!pirq) {
DBG(" -> not routed\n");
return 0;
}
DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs);
mask &= pcibios_irq_mask;
 
/* Work around broken HP Pavilion Notebooks which assign USB to
IRQ 9 even though it is actually wired to IRQ 11 */
 
if (broken_hp_bios_irq9 && pirq == 0x59 && dev->irq == 9) {
dev->irq = 11;
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11);
r->set(pirq_router_dev, dev, pirq, 11);
}
 
/*
* Find the best IRQ to assign: use the one
* reported by the device if possible.
*/
newirq = dev->irq;
if (!((1 << newirq) & mask)) {
if ( pci_probe & PCI_USE_PIRQ_MASK) newirq = 0;
else printk(KERN_WARNING "PCI: IRQ %i for device %s doesn't match PIRQ mask - try pci=usepirqmask\n", newirq, pci_name(dev));
}
if (!newirq && assign) {
for (i = 0; i < 16; i++) {
if (!(mask & (1 << i)))
continue;
if (pirq_penalty[i] < pirq_penalty[newirq] &&
!request_irq(i, pcibios_test_irq_handler, SA_SHIRQ, "pci-test", dev)) {
free_irq(i, dev);
newirq = i;
}
}
}
DBG(" -> newirq=%d", newirq);
 
/* Check if it is hardcoded */
if ((pirq & 0xf0) == 0xf0) {
irq = pirq & 0xf;
DBG(" -> hardcoded IRQ %d\n", irq);
msg = "Hardcoded";
} else if ( r->get && (irq = r->get(pirq_router_dev, dev, pirq)) && \
((!(pci_probe & PCI_USE_PIRQ_MASK)) || ((1 << irq) & mask)) ) {
DBG(" -> got IRQ %d\n", irq);
msg = "Found";
} else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
DBG(" -> assigning IRQ %d", newirq);
if (r->set(pirq_router_dev, dev, pirq, newirq)) {
eisa_set_level_irq(newirq);
DBG(" ... OK\n");
msg = "Assigned";
irq = newirq;
}
}
 
if (!irq) {
DBG(" ... failed\n");
if (newirq && mask == (1 << newirq)) {
msg = "Guessed";
irq = newirq;
} else
return 0;
}
printk(KERN_INFO "PCI: %s IRQ %d for device %s\n", msg, irq, pci_name(dev));
 
/* Update IRQ for all devices with the same pirq value */
while ((dev2 = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev2)) != NULL) {
pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin);
if (!pin)
continue;
pin--;
info = pirq_get_info(dev2);
if (!info)
continue;
if (info->irq[pin].link == pirq) {
/* We refuse to override the dev->irq information. Give a warning! */
if ( dev2->irq && dev2->irq != irq && \
(!(pci_probe & PCI_USE_PIRQ_MASK) || \
((1 << dev2->irq) & mask)) ) {
printk(KERN_INFO "IRQ routing conflict for %s, have irq %d, want irq %d\n",
pci_name(dev2), dev2->irq, irq);
continue;
}
dev2->irq = irq;
pirq_penalty[irq]++;
if (dev != dev2)
printk(KERN_INFO "PCI: Sharing IRQ %d with %s\n", irq, pci_name(dev2));
}
}
return 1;
}
 
static void __init pcibios_fixup_irqs(void)
{
struct pci_dev *dev = NULL;
u8 pin;
 
DBG("PCI: IRQ fixup\n");
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
/*
* If the BIOS has set an out of range IRQ number, just ignore it.
* Also keep track of which IRQ's are already in use.
*/
if (dev->irq >= 16) {
DBG("%s: ignoring bogus IRQ %d\n", pci_name(dev), dev->irq);
dev->irq = 0;
}
/* If the IRQ is already assigned to a PCI device, ignore its ISA use penalty */
if (pirq_penalty[dev->irq] >= 100 && pirq_penalty[dev->irq] < 100000)
pirq_penalty[dev->irq] = 0;
pirq_penalty[dev->irq]++;
}
 
dev = NULL;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
#ifdef CONFIG_X86_IO_APIC
/*
* Recalculate IRQ numbers if we use the I/O APIC.
*/
if (io_apic_assign_pci_irqs)
{
int irq;
 
if (pin) {
pin--; /* interrupt pins are numbered starting from 1 */
irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
/*
* Busses behind bridges are typically not listed in the MP-table.
* In this case we have to look up the IRQ based on the parent bus,
* parent slot, and pin number. The SMP code detects such bridged
* busses itself so we should get into this branch reliably.
*/
if (irq < 0 && dev->bus->parent) { /* go back to the bridge */
struct pci_dev * bridge = dev->bus->self;
 
pin = (pin + PCI_SLOT(dev->devfn)) % 4;
irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number,
PCI_SLOT(bridge->devfn), pin);
if (irq >= 0)
printk(KERN_WARNING "PCI: using PPB(B%d,I%d,P%d) to get irq %d\n",
bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq);
}
if (irq >= 0) {
printk(KERN_INFO "PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n",
dev->bus->number, PCI_SLOT(dev->devfn), pin, irq);
dev->irq = irq;
}
}
}
#endif
/*
* Still no IRQ? Try to lookup one...
*/
if (pin && !dev->irq)
pcibios_lookup_irq(dev, 0);
}
}
 
static int __init pcibios_irq_init(void)
{
DBG("PCI: IRQ init\n");
 
if (pcibios_enable_irq)
return 0;
 
pirq_table = pirq_find_routing_table();
 
#ifdef CONFIG_PCI_BIOS
if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN))
pirq_table = pcibios_get_irq_routing_table();
#endif
if (pirq_table) {
pirq_peer_trick();
pirq_find_router(&pirq_router);
if (pirq_table->exclusive_irqs) {
int i;
for (i=0; i<16; i++)
if (!(pirq_table->exclusive_irqs & (1 << i)))
pirq_penalty[i] += 100;
}
/* If we're using the I/O APIC, avoid using the PCI IRQ routing table */
if (io_apic_assign_pci_irqs)
pirq_table = NULL;
}
 
pcibios_enable_irq = pirq_enable_irq;
 
pcibios_fixup_irqs();
return 0;
}
 
subsys_initcall(pcibios_irq_init);
 
 
void pcibios_penalize_isa_irq(int irq)
{
/*
* If any ISAPnP device reports an IRQ in its list of possible
* IRQ's, we try to avoid assigning it to PCI devices.
*/
pirq_penalty[irq] += 100;
}
 
int pirq_enable_irq(struct pci_dev *dev)
{
u8 pin;
extern int interrupt_line_quirk;
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) {
char *msg;
if (io_apic_assign_pci_irqs)
msg = " Probably buggy MP table.";
else if (pci_probe & PCI_BIOS_IRQ_SCAN)
msg = "";
else
msg = " Please try using pci=biosirq.";
/* With IDE legacy devices the IRQ lookup failure is not a problem.. */
if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE && !(dev->class & 0x5))
return 0;
printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
'A' + pin - 1, pci_name(dev), msg);
}
/* VIA bridges use interrupt line for apic/pci steering across
the V-Link */
else if (interrupt_line_quirk)
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
return 0;
}
/shark/trunk/drivers/newpci/fixup.c
0,0 → 1,211
/*
* Exceptions for specific devices. Usually work-arounds for fatal design flaws.
*/
 
#include <linuxcomp.h>
 
#include <linux/pci.h>
#include <linux/init.h>
#include "pci2.h"
 
 
static void __devinit pci_fixup_i450nx(struct pci_dev *d)
{
/*
* i450NX -- Find and scan all secondary buses on all PXB's.
*/
int pxb, reg;
u8 busno, suba, subb;
 
printk(KERN_WARNING "PCI: Searching for i450NX host bridges on %s\n", pci_name(d));
reg = 0xd0;
for(pxb=0; pxb<2; pxb++) {
pci_read_config_byte(d, reg++, &busno);
pci_read_config_byte(d, reg++, &suba);
pci_read_config_byte(d, reg++, &subb);
DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
if (busno)
pci_scan_bus(busno, &pci_root_ops, NULL); /* Bus A */
if (suba < subb)
pci_scan_bus(suba+1, &pci_root_ops, NULL); /* Bus B */
}
pcibios_last_bus = -1;
}
 
static void __devinit pci_fixup_i450gx(struct pci_dev *d)
{
/*
* i450GX and i450KX -- Find and scan all secondary buses.
* (called separately for each PCI bridge found)
*/
u8 busno;
pci_read_config_byte(d, 0x4a, &busno);
printk(KERN_INFO "PCI: i440KX/GX host bridge %s: secondary bus %02x\n", pci_name(d), busno);
pci_scan_bus(busno, &pci_root_ops, NULL);
pcibios_last_bus = -1;
}
 
static void __devinit pci_fixup_umc_ide(struct pci_dev *d)
{
/*
* UM8886BF IDE controller sets region type bits incorrectly,
* therefore they look like memory despite of them being I/O.
*/
int i;
 
printk(KERN_WARNING "PCI: Fixing base address flags for device %s\n", pci_name(d));
for(i=0; i<4; i++)
d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
}
 
static void __devinit pci_fixup_ncr53c810(struct pci_dev *d)
{
/*
* NCR 53C810 returns class code 0 (at least on some systems).
* Fix class to be PCI_CLASS_STORAGE_SCSI
*/
if (!d->class) {
printk(KERN_WARNING "PCI: fixing NCR 53C810 class code for %s\n", pci_name(d));
d->class = PCI_CLASS_STORAGE_SCSI << 8;
}
}
 
static void __devinit pci_fixup_ide_bases(struct pci_dev *d)
{
int i;
 
/*
* PCI IDE controllers use non-standard I/O port decoding, respect it.
*/
if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
return;
DBG("PCI: IDE base address fixup for %s\n", pci_name(d));
for(i=0; i<4; i++) {
struct resource *r = &d->resource[i];
if ((r->start & ~0x80) == 0x374) {
r->start |= 2;
r->end = r->start;
}
}
}
 
static void __devinit pci_fixup_ide_trash(struct pci_dev *d)
{
int i;
 
/*
* There exist PCI IDE controllers which have utter garbage
* in first four base registers. Ignore that.
*/
DBG("PCI: IDE base address trash cleared for %s\n", pci_name(d));
for(i=0; i<4; i++)
d->resource[i].start = d->resource[i].end = d->resource[i].flags = 0;
}
 
static void __devinit pci_fixup_latency(struct pci_dev *d)
{
/*
* SiS 5597 and 5598 chipsets require latency timer set to
* at most 32 to avoid lockups.
*/
DBG("PCI: Setting max latency to 32\n");
pcibios_max_latency = 32;
}
 
static void __devinit pci_fixup_piix4_acpi(struct pci_dev *d)
{
/*
* PIIX4 ACPI device: hardwired IRQ9
*/
d->irq = 9;
}
 
/*
* Addresses issues with problems in the memory write queue timer in
* certain VIA Northbridges. This bugfix is per VIA's specifications,
* except for the KL133/KM133: clearing bit 5 on those Northbridges seems
* to trigger a bug in its integrated ProSavage video card, which
* causes screen corruption. We only clear bits 6 and 7 for that chipset,
* until VIA can provide us with definitive information on why screen
* corruption occurs, and what exactly those bits do.
*
* VIA 8363,8622,8361 Northbridges:
* - bits 5, 6, 7 at offset 0x55 need to be turned off
* VIA 8367 (KT266x) Northbridges:
* - bits 5, 6, 7 at offset 0x95 need to be turned off
* VIA 8363 rev 0x81/0x84 (KL133/KM133) Northbridges:
* - bits 6, 7 at offset 0x55 need to be turned off
*/
 
#define VIA_8363_KL133_REVISION_ID 0x81
#define VIA_8363_KM133_REVISION_ID 0x84
 
static void __devinit pci_fixup_via_northbridge_bug(struct pci_dev *d)
{
u8 v;
u8 revision;
int where = 0x55;
int mask = 0x1f; /* clear bits 5, 6, 7 by default */
 
pci_read_config_byte(d, PCI_REVISION_ID, &revision);
 
if (d->device == PCI_DEVICE_ID_VIA_8367_0) {
/* fix pci bus latency issues resulted by NB bios error
it appears on bug free^Wreduced kt266x's bios forces
NB latency to zero */
pci_write_config_byte(d, PCI_LATENCY_TIMER, 0);
 
where = 0x95; /* the memory write queue timer register is
different for the KT266x's: 0x95 not 0x55 */
} else if (d->device == PCI_DEVICE_ID_VIA_8363_0 &&
(revision == VIA_8363_KL133_REVISION_ID ||
revision == VIA_8363_KM133_REVISION_ID)) {
mask = 0x3f; /* clear only bits 6 and 7; clearing bit 5
causes screen corruption on the KL133/KM133 */
}
 
pci_read_config_byte(d, where, &v);
if (v & ~mask) {
printk(KERN_WARNING "Disabling VIA memory write queue (PCI ID %04x, rev %02x): [%02x] %02x & %02x -> %02x\n", \
d->device, revision, where, v, mask, v & mask);
v &= mask;
pci_write_config_byte(d, where, v);
}
}
 
/*
* For some reasons Intel decided that certain parts of their
* 815, 845 and some other chipsets must look like PCI-to-PCI bridges
* while they are obviously not. The 82801 family (AA, AB, BAM/CAM,
* BA/CA/DB and E) PCI bridges are actually HUB-to-PCI ones, according
* to Intel terminology. These devices do forward all addresses from
* system to PCI bus no matter what are their window settings, so they are
* "transparent" (or subtractive decoding) from programmers point of view.
*/
static void __devinit pci_fixup_transparent_bridge(struct pci_dev *dev)
{
if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
(dev->device & 0xff00) == 0x2400)
dev->transparent = 1;
}
 
struct pci_fixup pcibios_fixups[] = {
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, pci_fixup_ide_trash },
{ PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, pci_fixup_latency },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5598, pci_fixup_latency },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, pci_fixup_piix4_acpi },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10, pci_fixup_ide_trash },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_11, pci_fixup_ide_trash },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_9, pci_fixup_ide_trash },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, pci_fixup_via_northbridge_bug },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8622, pci_fixup_via_northbridge_bug },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, pci_fixup_via_northbridge_bug },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8367_0, pci_fixup_via_northbridge_bug },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, pci_fixup_ncr53c810 },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_fixup_transparent_bridge },
{ 0 }
};
/shark/trunk/drivers/newpci/makefile
12,7 → 12,8
 
OBJS = access.o bus.o names.o pci.o pci-driver.o pci-sysfs.o\
pool.o probe.o quirks.o remove.o search.o setup-res.o\
setup-irq.o setup-bus.o syscall.o
setup-irq.o setup-bus.o syscall.o i386.o common.o\
fixup.o irq.o legacy.o
 
OTHERINCL += -I$(BASE)/drivers/linuxc26/include
 
/shark/trunk/drivers/linuxc26/linuxcomp.c
1,13 → 1,64
 
#include <ll/i386/hw-instr.h>
#include <ll/i386/cons.h>
 
#include <linuxcomp.h>
 
#include <linux/time.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <asm/io.h>
 
int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
 
struct resource ioport_resource = {
.name = "PCI IO",
.start = 0x0000,
.end = IO_SPACE_LIMIT,
.flags = IORESOURCE_IO,
};
 
struct resource iomem_resource = {
.name = "PCI mem",
.start = 0UL,
.end = ~0UL,
.flags = IORESOURCE_MEM,
};
 
void __release_region(struct resource *parent, unsigned long start, unsigned long n) { }
 
struct resource * __request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name) {
return NULL;
}
 
void dump_stack(void) { }
 
void panic(const char * fmt, ...) {
 
cprintf((char *)(fmt));
 
}
 
extern void * malloc(size_t size);
 
void *__kmalloc(size_t size, int flags) {
 
return malloc(size);
 
}
 
extern void free(void *);
 
void kfree(const void *ptr) {
 
free((void *)(ptr));
 
return 0;
 
}
 
unsigned long pci_mem_start = 0x10000000;
 
signed long schedule_timeout(signed long timeout) {
 
SYS_FLAGS f;
20,9 → 71,26
 
nanosleep(&t,NULL);
 
cli();
ll_frestore(f);
 
return 0;
 
}
 
void __const_udelay(unsigned long usecs) {
 
SYS_FLAGS f;
struct timespec t;
f = ll_fsave();
sti();
t.tv_sec = 0;
t.tv_nsec = usecs * 1000;
nanosleep(&t,NULL);
ll_frestore(f);
}
 
/shark/trunk/drivers/linuxc26/include/linux/slab.h
76,24 → 76,6
 
static inline void *kmalloc(size_t size, int flags)
{
if (__builtin_constant_p(size)) {
int i = 0;
#define CACHE(x) \
if (size <= x) \
goto found; \
else \
i++;
#include "kmalloc_sizes.h"
#undef CACHE
{
extern void __you_cannot_kmalloc_that_much(void);
__you_cannot_kmalloc_that_much();
}
found:
return kmem_cache_alloc((flags & GFP_DMA) ?
malloc_sizes[i].cs_dmacachep :
malloc_sizes[i].cs_cachep, flags);
}
return __kmalloc(size, flags);
}