/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, ®); |
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); |
} |