mirror of
https://github.com/fail0verflow/switch-coreboot.git
synced 2025-05-04 01:39:18 -04:00
496 lines
16 KiB
C
496 lines
16 KiB
C
/*
|
|
* $Id$
|
|
*
|
|
* PCI Bus Services, see include/linux/pci.h for further explanation.
|
|
*
|
|
* Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter,
|
|
* David Mosberger-Tang
|
|
*
|
|
* Copyright 1997 -- 1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
|
|
*/
|
|
|
|
#ifndef lint
|
|
static char rcsid[] = "$Id$";
|
|
#endif
|
|
|
|
#include <pci.h>
|
|
#include <pci_ids.h>
|
|
#include <cpu/p5/io.h>
|
|
#include <printk.h>
|
|
#include <types.h>
|
|
|
|
extern void intel_post(unsigned char value);
|
|
|
|
#undef DEBUGSCAN
|
|
#ifdef DEBUGSCAN
|
|
#define DBGSCAN(x...) printk(KERN_DEBUG x)
|
|
#else
|
|
#define DBGSCAN(x...)
|
|
#endif
|
|
|
|
/**
|
|
* This is the root of the PCI tree. A PCI tree always has
|
|
* one bus, bus 0. Bus 0 contains devices and bridges.
|
|
*/
|
|
struct pci_bus pci_root;
|
|
/// Linked list of PCI devices. ALL devices are on this list
|
|
struct pci_dev *pci_devices = 0;
|
|
/// pointer to the last device */
|
|
static struct pci_dev **pci_last_dev_p = &pci_devices;
|
|
/// We're going to probably delete this -- flag to add in reverse order */
|
|
static int pci_reverse = 0;
|
|
|
|
/**
|
|
* Given a bus and a devfn number, find the device structure
|
|
* @param bus The bus number
|
|
* @param devfn a device/function number
|
|
* @return pointer to the device structure
|
|
*/
|
|
struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn)
|
|
{
|
|
struct pci_dev *dev;
|
|
|
|
for (dev = pci_devices; dev; dev = dev->next)
|
|
if (dev->bus->number == bus && dev->devfn == devfn)
|
|
break;
|
|
return dev;
|
|
}
|
|
|
|
/** Find a device of a given vendor and type
|
|
* @param vendor Vendor ID (e.g. 0x8086 for Intel)
|
|
* @param device Device ID
|
|
* @param from Pointer to the device structure, used as a starting point
|
|
* in the linked list of devices, which can be 0 to start at the
|
|
* head of the list (i.e. pci_devices)
|
|
* @return Pointer to the device struct
|
|
*/
|
|
struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device, struct pci_dev *from)
|
|
{
|
|
if (!from)
|
|
from = pci_devices;
|
|
else
|
|
from = from->next;
|
|
while (from && (from->vendor != vendor || from->device != device))
|
|
from = from->next;
|
|
return from;
|
|
}
|
|
|
|
/** Find a device of a given class
|
|
* @param class Class of the device
|
|
* @param from Pointer to the device structure, used as a starting point
|
|
* in the linked list of devices, which can be 0 to start at the
|
|
* head of the list (i.e. pci_devices)
|
|
* @return Pointer to the device struct
|
|
*/
|
|
struct pci_dev *pci_find_class(unsigned int class, struct pci_dev *from)
|
|
{
|
|
if (!from)
|
|
from = pci_devices;
|
|
else
|
|
from = from->next;
|
|
while (from && from->class != class)
|
|
from = from->next;
|
|
return from;
|
|
}
|
|
|
|
/** Given a device, set the PCI_COMMAND_MASTER bit in the command register
|
|
* @param dev Pointer to the device structure
|
|
*/
|
|
void pci_set_master(struct pci_dev *dev)
|
|
{
|
|
u16 cmd;
|
|
u8 lat;
|
|
|
|
pci_read_config_word(dev, PCI_COMMAND, &cmd);
|
|
if (!(cmd & PCI_COMMAND_MASTER)) {
|
|
DBG("PCI: Enabling bus mastering for device %02x:%02x\n",
|
|
dev->bus->number, dev->devfn);
|
|
cmd |= PCI_COMMAND_MASTER;
|
|
pci_write_config_word(dev, PCI_COMMAND, cmd);
|
|
}
|
|
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
|
|
if (lat < 16) {
|
|
DBG("PCI: Increasing latency timer of device %02x:%02x to 64\n",
|
|
dev->bus->number, dev->devfn);
|
|
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
|
|
}
|
|
}
|
|
|
|
/** Given a device and register, read the size of the BAR for that register.
|
|
* @param dev Pointer to the device structure
|
|
* @param reg Which register to use
|
|
* @param addr Address to load into the register after size is found
|
|
*/
|
|
void pci_get_size(struct pci_dev *dev, unsigned long reg, unsigned long addr)
|
|
{
|
|
u32 size;
|
|
unsigned long type;
|
|
|
|
/* FIXME: more consideration for 64-bit PCI devices */
|
|
// get the size
|
|
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), ~0);
|
|
pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &size);
|
|
|
|
// restore addr
|
|
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), addr);
|
|
|
|
// Now compute the actual size, See PCI Spec 6.2.5.1 ...
|
|
if (size & PCI_BASE_ADDRESS_SPACE_IO) {
|
|
type = size & (~PCI_BASE_ADDRESS_IO_MASK);
|
|
size &= (PCI_BASE_ADDRESS_IO_MASK);
|
|
// BUG! Top 16 bits can be zero (or not)
|
|
// So set them to 0xffff so they go away ...
|
|
size |= 0xffff0000;
|
|
size = ~size;
|
|
size++;
|
|
} else {
|
|
type = size & (~PCI_BASE_ADDRESS_MEM_MASK);
|
|
size &= (PCI_BASE_ADDRESS_MEM_MASK);
|
|
size = ~size;
|
|
size++;
|
|
}
|
|
dev->size[reg] = size | type;
|
|
}
|
|
|
|
/** Read the base address registers for a given device.
|
|
* @param dev Pointer to the dev structure
|
|
* @param howmany How many registers to read (6 for device, 2 for bridge)
|
|
*/
|
|
void pci_read_bases(struct pci_dev *dev, unsigned int howmany)
|
|
{
|
|
unsigned int reg;
|
|
u32 /* unsigned long for 64 bits ?? */ addr;
|
|
|
|
/* FIXME: to deal with 64-bits PCI */
|
|
for (reg = 0; reg < howmany; reg++) {
|
|
pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &addr);
|
|
if (addr == 0xffffffff)
|
|
continue;
|
|
|
|
/* get address space size */
|
|
pci_get_size(dev, reg, addr);
|
|
|
|
addr &= (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK);
|
|
if (addr == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
|
|
DBG("reg %d is 64-bit\n", reg);
|
|
/* this is a 64-bit memory base address */
|
|
reg++;
|
|
pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &addr);
|
|
if (addr) {
|
|
#if BITS_PER_LONG == 64
|
|
dev->base_address[reg - 1] |= ((unsigned long) addr) << 32;
|
|
#else
|
|
printk(KERN_ERR "PCI: Unable to handle 64-bit address for device "
|
|
"%02x:%02x\n", dev->bus->number, dev->devfn);
|
|
dev->base_address[reg - 1] = 0;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Scan the bus, first for bridges and next for devices.
|
|
* @param pci_bus pointer to the bus structure
|
|
* @return The maximum bus number found, after scanning all subordinate busses
|
|
*/
|
|
unsigned int pci_scan_bus(struct pci_bus *bus)
|
|
{
|
|
unsigned int devfn, max;
|
|
struct pci_dev *dev, **bus_last;
|
|
struct pci_bus *child;
|
|
|
|
DBG("PCI: pci_scan_bus for bus %d\n", bus->number);
|
|
|
|
bus_last = &bus->devices;
|
|
max = bus->secondary;
|
|
|
|
intel_post(0x24);
|
|
|
|
/* probe all devices on this bus with some optimization for non-existance and
|
|
single funcion devices */
|
|
for (devfn = 0; devfn < 0xff; devfn++) {
|
|
u32 id, class, addr;
|
|
u8 cmd, tmp, hdr_type;
|
|
|
|
// gcc just went to hell. Don't test -- this always
|
|
// returns 0 anyway.
|
|
#if GCC_WORKS_ON_O2
|
|
if (pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID, &id)) {
|
|
DBGSCAN("PCI: devfn 0x%x, read_config_dword fails\n",
|
|
devfn);
|
|
continue;
|
|
}
|
|
#endif
|
|
pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID, &id);
|
|
|
|
/* some broken boards return 0 if a slot is empty: */
|
|
if (id == 0xffffffff || id == 0x00000000 || id == 0x0000ffff || id == 0xffff0000) {
|
|
DBGSCAN("PCI: devfn 0x%x, bad id 0x%x\n", devfn, id);
|
|
if (PCI_FUNC(devfn) == 0x00) {
|
|
/* if this is a function 0 device and it is not present,
|
|
skip to next device */
|
|
devfn += 0x07;
|
|
}
|
|
/* multi function device, skip to next function */
|
|
continue;
|
|
}
|
|
|
|
if (pcibios_read_config_byte(bus->number, devfn, PCI_HEADER_TYPE, &hdr_type)){
|
|
DBGSCAN("PCI: devfn 0x%x, header type read fails\n", devfn);
|
|
continue;
|
|
}
|
|
|
|
if (pcibios_read_config_dword(bus->number, devfn, PCI_CLASS_REVISION, &class)) {
|
|
DBGSCAN("PCI: devfn 0x%x, class read fails\n", devfn);
|
|
continue;
|
|
}
|
|
|
|
if ((dev = kmalloc(sizeof(*dev), GFP_ATOMIC)) == 0) {
|
|
printk(KERN_ERR "PCI: out of memory.\n");
|
|
continue;
|
|
}
|
|
|
|
memset(dev, 0, sizeof(*dev));
|
|
dev->bus = bus;
|
|
dev->devfn = devfn;
|
|
dev->vendor = id & 0xffff;
|
|
dev->device = (id >> 16) & 0xffff;
|
|
dev->hdr_type = hdr_type;
|
|
/* class code, the upper 3 bytes of PCI_CLASS_REVISION */
|
|
dev->class = class >> 8;
|
|
class >>= 16;
|
|
|
|
/* non-destructively determine if device can be a master: */
|
|
pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND, &cmd);
|
|
pcibios_write_config_byte(bus->number, devfn, PCI_COMMAND,
|
|
cmd | PCI_COMMAND_MASTER);
|
|
pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND, &tmp);
|
|
dev->master = ((tmp & PCI_COMMAND_MASTER) != 0);
|
|
pcibios_write_config_byte(bus->number, devfn, PCI_COMMAND, cmd);
|
|
|
|
switch (hdr_type & 0x7f) { /* header type */
|
|
case PCI_HEADER_TYPE_NORMAL: /* standard header */
|
|
if (class == PCI_CLASS_BRIDGE_PCI)
|
|
goto bad;
|
|
/* read base address registers, again pci_fixup() can tweak these */
|
|
pci_read_bases(dev, 6);
|
|
pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS, &addr);
|
|
dev->rom_address = (addr == 0xffffffff) ? 0 : addr;
|
|
break;
|
|
case PCI_HEADER_TYPE_BRIDGE: /* bridge header */
|
|
if (class != PCI_CLASS_BRIDGE_PCI)
|
|
goto bad;
|
|
pci_read_bases(dev, 2);
|
|
pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS1, &addr);
|
|
dev->rom_address = (addr == 0xffffffff) ? 0 : addr;
|
|
break;
|
|
case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */
|
|
if (class != PCI_CLASS_BRIDGE_CARDBUS)
|
|
goto bad;
|
|
pci_read_bases(dev, 1);
|
|
break;
|
|
default: /* unknown header */
|
|
bad:
|
|
printk(KERN_ERR "PCI: %02x:%02x [%04x/%04x/%06x] has unknown header "
|
|
"type %02x, ignoring.\n",
|
|
bus->number, dev->devfn, dev->vendor, dev->device, class,
|
|
hdr_type);
|
|
continue;
|
|
}
|
|
|
|
DBG("PCI: %02x:%02x [%04x/%04x]\n", bus->number, dev->devfn,
|
|
dev->vendor, dev->device);
|
|
|
|
/* Put it into the global PCI device chain. It's used to find devices once
|
|
everything is set up. */
|
|
if (!pci_reverse) {
|
|
*pci_last_dev_p = dev;
|
|
pci_last_dev_p = &dev->next;
|
|
} else {
|
|
dev->next = pci_devices;
|
|
pci_devices = dev;
|
|
}
|
|
|
|
/* Now insert it into the list of devices held by the parent bus. */
|
|
*bus_last = dev;
|
|
bus_last = &dev->sibling;
|
|
|
|
if (PCI_FUNC(devfn) == 0x00 && (hdr_type & 0x80) != 0x80) {
|
|
/* if this is not a multi function device, don't waste time probe
|
|
another function. Skip to next device. */
|
|
devfn += 0x07;
|
|
}
|
|
}
|
|
|
|
intel_post(0x25);
|
|
/*
|
|
* After performing arch-dependent fixup of the bus, look behind
|
|
* all PCI-to-PCI bridges on this bus.
|
|
*/
|
|
//pcibios_fixup_bus(bus);
|
|
/*
|
|
* The fixup code may have just found some peer pci bridges on this
|
|
* machine. Update the max variable if that happened so we don't
|
|
* get duplicate bus numbers.
|
|
*/
|
|
for (child = &pci_root; child; child = child->next)
|
|
max = ((max > child->subordinate) ? max : child->subordinate);
|
|
|
|
for (dev = bus->devices; dev; dev = dev->sibling)
|
|
/* If it's a bridge, scan the bus behind it. */
|
|
if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
|
|
u32 buses;
|
|
unsigned int devfn = dev->devfn;
|
|
unsigned short cr;
|
|
#define NOTUSED
|
|
#ifdef NOTUSED
|
|
/*
|
|
* Check for a duplicate bus. If we already scanned
|
|
* this bus number as a peer bus, don't also scan it
|
|
* as a child bus
|
|
*/
|
|
if (((dev->vendor == PCI_VENDOR_ID_SERVERWORKS) &&
|
|
((dev->device == PCI_DEVICE_ID_SERVERWORKS_HE) ||
|
|
(dev->device == PCI_DEVICE_ID_SERVERWORKS_LE))) ||
|
|
((dev->vendor == PCI_VENDOR_ID_COMPAQ) &&
|
|
(dev->device == PCI_DEVICE_ID_COMPAQ_6010)) ||
|
|
((dev->vendor == PCI_VENDOR_ID_INTEL) &&
|
|
((dev->device == PCI_DEVICE_ID_INTEL_82454NX)||
|
|
(dev->device == PCI_DEVICE_ID_INTEL_82451NX))))
|
|
goto skip_it;
|
|
|
|
/* Read the existing primary/secondary/subordinate bus number
|
|
configuration to determine if the PCI bridge has already been
|
|
configured by the system. If so, check to see if we've already
|
|
scanned this bus as a result of peer bus scanning, if so, skip this.
|
|
FIMXE: We are BIOS, is there anyone else doing this dirty job BEFORE us ?? */
|
|
pcibios_read_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, &buses);
|
|
if ((buses & 0xFFFFFF) != 0) {
|
|
for (child = pci_root.next; child; child = child->next)
|
|
if (child->number == ((buses >> 8) & 0xff))
|
|
goto skip_it;
|
|
}
|
|
#endif
|
|
/* Insert it into the tree of buses. */
|
|
if ((child = kmalloc(sizeof(*child), GFP_ATOMIC)) == 0) {
|
|
printk(KERN_ERR "PCI: out of memory for bridge.\n");
|
|
continue;
|
|
}
|
|
memset(child, 0, sizeof(*child));
|
|
child->next = bus->children;
|
|
bus->children = child;
|
|
child->self = dev;
|
|
child->parent = bus;
|
|
|
|
/* Set up the primary, secondary and subordinate bus numbers. We have
|
|
no idea how many buses are behind this bridge yet, so we set the
|
|
subordinate bus number to 0xff for the moment */
|
|
child->number = child->secondary = ++max;
|
|
child->primary = bus->secondary;
|
|
child->subordinate = 0xff;
|
|
|
|
/* Clear all status bits and turn off memory, I/O and master enables. */
|
|
pcibios_read_config_word(bus->number, devfn, PCI_COMMAND, &cr);
|
|
pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, 0x0000);
|
|
pcibios_write_config_word(bus->number, devfn, PCI_STATUS, 0xffff);
|
|
|
|
/*
|
|
* Read the existing primary/secondary/subordinate bus
|
|
* number configuration to determine if the PCI bridge
|
|
* has already been configured by the system. If so,
|
|
* do not modify the configuration, merely note it.
|
|
*/
|
|
pcibios_read_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, &buses);
|
|
|
|
#ifdef BRIDGE_CONFIGURED_AT_POWERUP
|
|
// There is some hardware (ALPHA) that configures bridges in hardware, at bootup.
|
|
// We need to take that into account at some point.
|
|
// At the same time, we're finding buggy bridge hardware that comes up
|
|
// with these registers non-zero (VIA VT8601). Hence this #ifdef -- in some cases,
|
|
// you should never check the buses; in other cases, you have no choice.
|
|
if ((buses & 0xFFFFFF) != 0) {
|
|
unsigned int cmax;
|
|
|
|
child->primary = buses & 0xFF;
|
|
child->secondary = (buses >> 8) & 0xFF;
|
|
child->subordinate = (buses >> 16) & 0xFF;
|
|
child->number = child->secondary;
|
|
cmax = pci_scan_bus(child);
|
|
if (cmax > max)
|
|
max = cmax;
|
|
} else
|
|
#endif
|
|
{
|
|
/* Configure the bus numbers for this bridge: the configuration
|
|
transactions will not be propagated by the bridge if it is not
|
|
correctly configured */
|
|
buses &= 0xff000000;
|
|
buses |= (((unsigned int) (child->primary) << 0) |
|
|
((unsigned int) (child->secondary) << 8) |
|
|
((unsigned int) (child->subordinate) << 16));
|
|
pcibios_write_config_dword(bus->number, devfn,
|
|
PCI_PRIMARY_BUS, buses);
|
|
|
|
/* Now we can scan all subordinate buses i.e. the bus hehind the bridge */
|
|
max = pci_scan_bus(child);
|
|
|
|
/* We know the number of buses behind this bridge. Set the subordinate
|
|
bus number to its real value */
|
|
child->subordinate = max;
|
|
buses = (buses & 0xff00ffff) |
|
|
((unsigned int) (child->subordinate) << 16);
|
|
pcibios_write_config_dword(bus->number, devfn,
|
|
PCI_PRIMARY_BUS, buses);
|
|
}
|
|
|
|
pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, cr);
|
|
skip_it:
|
|
}
|
|
/*
|
|
* We've scanned the bus and so we know all about what's on
|
|
* the other side of any bridges that may be on this bus plus
|
|
* any devices.
|
|
*
|
|
* Return how far we've got finding sub-buses.
|
|
*/
|
|
DBG("PCI: pci_scan_bus returning with max=%02x\n", max);
|
|
intel_post(0x55);
|
|
return max;
|
|
}
|
|
|
|
/** Scan a peer bridge.
|
|
* First, scan all the bus structs for this bus number. If this bus
|
|
* is found, that means it was configured, so just return the pointer.
|
|
* If the bus is not found, it needs to be configured. Allocate memory
|
|
* for the struct, link it in to the linked list of bridges, and then
|
|
* scan it.
|
|
* @param bus The bus number supported by the peer bridge
|
|
* @return Pointer to the bus struct for this bus number.
|
|
*/
|
|
struct pci_bus *pci_scan_peer_bridge(int bus)
|
|
{
|
|
struct pci_bus *b;
|
|
|
|
b = &pci_root;
|
|
while ((b != 0) && (bus != 0)) {
|
|
if (b->number == bus)
|
|
return (b);
|
|
b = b->next;
|
|
}
|
|
b = kmalloc(sizeof(*b), GFP_KERNEL);
|
|
memset(b, 0, sizeof(*b));
|
|
b->next = pci_root.next;
|
|
pci_root.next = b;
|
|
b->number = b->secondary = bus;
|
|
b->subordinate = pci_scan_bus(b);
|
|
return b;
|
|
}
|
|
|
|
/** Initialize pci root struct, then scan starting at the root.
|
|
* Note that this function will recurse at each bridge.
|
|
*/
|
|
void pci_init(void)
|
|
{
|
|
memset(&pci_root, 0, sizeof(pci_root));
|
|
pci_root.subordinate = pci_scan_bus(&pci_root);
|
|
}
|