I've been trying to figure out how the division of work between
config_manager and busses works, and this is a large correction based on my current working thoughts. I also think we need to have a new interface between the bus modules and the config_manager to allow them to work together. I have some ideas on it and will start fleshing it out next week. This update basically moves all PCI stuff back to the PCI module and cleans up config_manager.c. We now print a small amount of info for devices and more for bridges. My system only has a single bridge, but if anyone has a more exotic system and tries this can they let me know what sort of results they see? git-svn-id: file:///srv/svn/repos/haiku/trunk/current@444 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
d6758977e7
commit
a0bc23f288
@ -13,17 +13,8 @@
|
||||
#include <string.h>
|
||||
#include <memheap.h>
|
||||
|
||||
/* This is normally turned off. Turning it on (1) will provide a more
|
||||
* verbose description of the PCI devices found, though most of the extra
|
||||
* information is only useful if you're working on this code.
|
||||
*/
|
||||
#define THE_FULL_MONTY 0
|
||||
|
||||
static pci_module_info *pcim = NULL;
|
||||
|
||||
static void pci_scan_bus(uint8 bus);
|
||||
static void pci_bridge(uint8 bus, uint8 dev, uint8 func);
|
||||
|
||||
#define B_CONFIG_MANAGER_FOR_BUS_MODULE_NAME "bus_managers/config_manager/bus/v1"
|
||||
|
||||
static status_t cfdm_get_next_device_info(bus_type bus, uint64 *cookie,
|
||||
@ -33,346 +24,7 @@ static status_t cfdm_get_next_device_info(bus_type bus, uint64 *cookie,
|
||||
bus, *cookie);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *decode_class(uint8 base, uint8 sub_class)
|
||||
{
|
||||
switch(base) {
|
||||
case PCI_early:
|
||||
switch (sub_class) {
|
||||
case PCI_early_not_vga:
|
||||
return "legacy (non VGA)";
|
||||
case PCI_early_vga:
|
||||
return "legacy VGA";
|
||||
}
|
||||
case 0x01:
|
||||
switch (sub_class) {
|
||||
case PCI_scsi:
|
||||
return "mass storage controller: scsi";
|
||||
case PCI_ide:
|
||||
return "mass storage controller: ide";
|
||||
case PCI_floppy:
|
||||
return "mass storage controller: floppy";
|
||||
case PCI_ipi:
|
||||
return "mass storage controller: ipi";
|
||||
case PCI_raid:
|
||||
return "mass storage controller: raid";
|
||||
case PCI_mass_storage_other:
|
||||
return "mass storage controller: other";
|
||||
}
|
||||
case 0x02:
|
||||
switch (sub_class) {
|
||||
case PCI_ethernet:
|
||||
return "network controller: ethernet";
|
||||
case PCI_token_ring:
|
||||
return "network controller: token ring";
|
||||
case PCI_fddi:
|
||||
return "network controller: fddi";
|
||||
case PCI_atm:
|
||||
return "network controller: atm";
|
||||
case PCI_network_other:
|
||||
return "network controller: other";
|
||||
}
|
||||
case 0x03:
|
||||
switch (sub_class) {
|
||||
case PCI_vga:
|
||||
return "display controller: vga";
|
||||
case PCI_xga:
|
||||
return "display controller: xga";
|
||||
case PCI_display_other:
|
||||
return "display controller: other";
|
||||
}
|
||||
case 0x04:
|
||||
switch (sub_class) {
|
||||
case PCI_video:
|
||||
return "multimedia device: video";
|
||||
case PCI_audio:
|
||||
return "multimedia device: audio";
|
||||
case PCI_multimedia_other:
|
||||
return "multimedia device: other";
|
||||
}
|
||||
case 0x05: return "memory controller";
|
||||
case 0x06:
|
||||
switch (sub_class) {
|
||||
case PCI_host:
|
||||
return "bridge controller: host bridge";
|
||||
case PCI_isa:
|
||||
return "bridge controller: isa";
|
||||
case PCI_eisa:
|
||||
return "bridge controller: eisa";
|
||||
case PCI_microchannel:
|
||||
return "bridge controller: microchannel";
|
||||
case PCI_pci:
|
||||
return "bridge controller: PCI";
|
||||
case PCI_pcmcia:
|
||||
return "bridge controller: PC Card";
|
||||
case PCI_nubus:
|
||||
return "bridge controller: nubus";
|
||||
case PCI_cardbus:
|
||||
return "bridge controller: CardBus";
|
||||
case PCI_bridge_other:
|
||||
return "bridge controller: other";
|
||||
}
|
||||
case 0x07: return "simple comms controller";
|
||||
case 0x08: return "base system peripheral";
|
||||
case 0x09: return "input device";
|
||||
case 0x0a: return "docking station";
|
||||
case 0x0b: return "processor";
|
||||
case 0x0c:
|
||||
switch (sub_class) {
|
||||
case PCI_firewire:
|
||||
return "bus controller: IEEE1394 FireWire";
|
||||
case PCI_access:
|
||||
return "bus controller: ACCESS.bus";
|
||||
case PCI_ssa:
|
||||
return "bus controller: SSA";
|
||||
case PCI_usb:
|
||||
return "bus controller: USB";
|
||||
case PCI_fibre_channel:
|
||||
return "bus controller: fibre channel";
|
||||
}
|
||||
case 0x0d: return "wireless";
|
||||
case 0x0e: return "intelligent i/o ??";
|
||||
case 0x0f: return "satellite";
|
||||
case 0x10: return "encryption";
|
||||
case 0x11: return "signal processing";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static void show_pci_details(struct pci_info *p, pci_module_info *pcim)
|
||||
{
|
||||
#if THE_FULL_MONTY
|
||||
uint16 ss_vend, ss_dev;
|
||||
#endif
|
||||
uint8 irq = 0;
|
||||
|
||||
if (p->header_type == PCI_header_type_generic)
|
||||
irq = p->u.h0.interrupt_line;
|
||||
else
|
||||
irq = p->u.h1.interrupt_line;
|
||||
|
||||
dprintf("0x%04x:0x%04x : ", p->vendor_id, p->device_id);
|
||||
|
||||
if (irq > 0)
|
||||
dprintf("irq %d : ", irq);
|
||||
|
||||
dprintf("location %d:%d:%d : ", p->bus, p->device, p->function);
|
||||
dprintf("class %02x:%02x:%02x", p->class_base, p->class_sub,
|
||||
p->class_api);
|
||||
dprintf(" => %s\n", decode_class(p->class_base, p->class_sub));
|
||||
|
||||
#if THE_FULL_MONTY
|
||||
dprintf("\trevision : %02x\n", p->revision);
|
||||
dprintf("\tstatus : %04x\n",
|
||||
pcim->read_pci_config(p->bus, p->device, p->function, PCI_status, 2));
|
||||
dprintf("\tcommand : %04x\n",
|
||||
pcim->read_pci_config(p->bus, p->device, p->function, PCI_command, 2));
|
||||
dprintf("\tbase address: %08x\n",
|
||||
pcim->read_pci_config(p->bus, p->device, p->function, PCI_base_registers, 4));
|
||||
|
||||
dprintf("\tline_size : %02x\n", p->line_size);
|
||||
dprintf("\theader_type : %02x\n", p->header_type);
|
||||
dprintf("\tbist : %02x\n", p->bist);
|
||||
|
||||
if (p->header_type == PCI_header_type_generic) {
|
||||
dprintf("Header Type 0 (Generic)\n");
|
||||
dprintf("\tcardbus_cis : %08lx\n", p->u.h0.cardbus_cis);
|
||||
dprintf("\trom_base_pci : %08lx\n", p->u.h0.rom_base_pci);
|
||||
dprintf("\tinterrupt_line : %02x\n", p->u.h0.interrupt_line);
|
||||
dprintf("\tinterrupt_pin : %02x\n", p->u.h0.interrupt_pin);
|
||||
ss_vend = p->u.h0.subsystem_vendor_id;
|
||||
ss_dev = p->u.h0.subsystem_id;
|
||||
} else if (p->header_type == PCI_header_type_PCI_to_PCI_bridge) {
|
||||
dprintf("Header Type 1 (PCI-PCI bridge)\n");
|
||||
dprintf("\trom_base_pci : %08lx\n", p->u.h1.rom_base_pci);
|
||||
dprintf("\tinterrupt_line : %02x\n", p->u.h1.interrupt_line);
|
||||
dprintf("\tinterrupt_pin : %02x\n", p->u.h1.interrupt_pin);
|
||||
dprintf("\t2ndry status : %04x\n", p->u.h1.secondary_status);
|
||||
dprintf("\tprimary_bus : %d\n", p->u.h1.primary_bus);
|
||||
dprintf("\tsecondary_bus : %d\n", p->u.h1.secondary_bus);
|
||||
dprintf("\tbridge control : %02x\n", p->u.h1.bridge_control);
|
||||
ss_vend = p->u.h1.subsystem_vendor_id;
|
||||
ss_dev = p->u.h1.subsystem_id;
|
||||
}
|
||||
dprintf("\tsubsystem_id : %04x\n", ss_dev);
|
||||
dprintf("\tsubsystem_vendor_id : %04x\n", ss_vend);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* XXX - move these to a header file */
|
||||
#define PCI_VENDOR_INTEL 0x8086
|
||||
|
||||
#define PCI_PRODUCT_INTEL_82371AB_ISA 0x7110 /* PIIX4 ISA */
|
||||
#define PCI_PRODUCT_INTEL_82371AB_IDE 0x7111 /* PIIX4 IDE */
|
||||
#define PCI_PRODUCT_INTEL_82371AB_USB 0x7112 /* PIIX4 USB */
|
||||
#define PCI_PRODUCT_INTEL_82371AB_PMC 0x7113 /* PIIX4 Power Management */
|
||||
|
||||
#define PCI_PRODUCT_INTEL_82443BX 0x7190
|
||||
#define PCI_PRODUCT_INTEL_82443BX_AGP 0x7191
|
||||
#define PCI_PRODUCT_INTEL_82443BX_NOAGP 0x7192
|
||||
|
||||
|
||||
/* Borrowed from NetBSD.
|
||||
* Some Host bridges need to have fixes applied.
|
||||
*/
|
||||
static void fixup_host_bridge(uint8 bus, uint8 dev, uint8 func)
|
||||
{
|
||||
uint16 vendor, device;
|
||||
|
||||
vendor = pcim->read_pci_config(bus, dev, func, PCI_vendor_id, 2);
|
||||
device = pcim->read_pci_config(bus, dev, func, PCI_device_id, 2);
|
||||
|
||||
switch (vendor) {
|
||||
case PCI_VENDOR_INTEL:
|
||||
switch (device) {
|
||||
case PCI_PRODUCT_INTEL_82443BX_AGP:
|
||||
case PCI_PRODUCT_INTEL_82443BX_NOAGP: {
|
||||
/* BIOS bug workaround
|
||||
* While the datasheet indicates that the only valid setting
|
||||
* for "Idle/Pipeline DRAM Leadoff Timing (IPLDT)" is 01,
|
||||
* some BIOS's do not set these correctly, so we check and
|
||||
* correct if required.
|
||||
*/
|
||||
uint16 bcreg = pcim->read_pci_config(bus, dev, func, 0x76, 2);
|
||||
if ((bcreg & 0x0300) != 0x0100) {
|
||||
dprintf("Intel 82443BX Host Bridge: Fixing IPDLT setting\n");
|
||||
bcreg &= ~0x0300;
|
||||
bcreg |= 0x100;
|
||||
pcim->write_pci_config(bus, dev, func, 0x76, 2, bcreg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Given a vendor/device pairing, do we need to scan through
|
||||
* the entire set of funtions? normally the return will be 0,
|
||||
* implying we don't need to, but for some it will be 1 which
|
||||
* means scan all functions.
|
||||
* This function may seem overkill but it prevents scanning
|
||||
* functions we don't need to and shoudl reduce the possibility of
|
||||
* duplicates being detected.
|
||||
*/
|
||||
static int pci_quirk_multifunction(uint16 vendor, uint16 device)
|
||||
{
|
||||
switch (vendor) {
|
||||
case PCI_VENDOR_INTEL:
|
||||
switch (device) {
|
||||
case PCI_PRODUCT_INTEL_82371AB_ISA:
|
||||
case PCI_PRODUCT_INTEL_82371AB_IDE:
|
||||
case PCI_PRODUCT_INTEL_82371AB_USB:
|
||||
case PCI_PRODUCT_INTEL_82371AB_PMC:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* pci_bridge()
|
||||
* The values passed in specify the "device" on the bus being searched
|
||||
* that has been identified as a PCI-PCI bridge. We now setup that bridge
|
||||
* and scan the bus it defines.
|
||||
* The bus is initially taken off-line, scanned and then put back on-line
|
||||
*/
|
||||
static void pci_bridge(uint8 bus, uint8 dev, uint8 func)
|
||||
{
|
||||
uint16 command = 0;
|
||||
uint8 mybus = bus + 1;
|
||||
|
||||
command = pcim->read_pci_config(bus, dev, func, PCI_command, 2);
|
||||
command &= ~ 0x03;
|
||||
pcim->write_pci_config(bus, dev, func, PCI_command, 2, command);
|
||||
|
||||
/* Bus is now off line */
|
||||
|
||||
pcim->write_pci_config(bus, dev, func, PCI_primary_bus, 1, bus);
|
||||
pcim->write_pci_config(bus, dev, func, PCI_secondary_bus, 1, mybus);
|
||||
pcim->write_pci_config(bus, dev, func, PCI_subordinate_bus, 1, 0xff);
|
||||
|
||||
dprintf("PCI-PCI bridge at %d:%d:%d configured as bus %d\n", bus, dev, func, mybus);
|
||||
pci_scan_bus(mybus);
|
||||
|
||||
/* Not strictly correct, but close enough... */
|
||||
command |= 0x03;
|
||||
pcim->write_pci_config(bus, dev, func, PCI_command, 2, command);
|
||||
}
|
||||
|
||||
static void pci_device_probe(uint8 bus, uint8 dev, uint8 func)
|
||||
{
|
||||
uint8 base_class, sub_class;
|
||||
uint8 type;
|
||||
|
||||
if (func > 0) {
|
||||
uint16 vend = pcim->read_pci_config(bus, dev, func, PCI_vendor_id, 2);
|
||||
if (vend == 0xffff)
|
||||
return;
|
||||
}
|
||||
|
||||
type = pcim->read_pci_config(bus, dev, func, PCI_header_type, 1);
|
||||
type &= PCI_header_type_mask;
|
||||
base_class = pcim->read_pci_config(bus, dev, func, PCI_class_base, 1);
|
||||
sub_class = pcim->read_pci_config(bus, dev, func, PCI_class_sub, 1);
|
||||
|
||||
if (base_class == PCI_bridge) {
|
||||
if (sub_class == PCI_host)
|
||||
fixup_host_bridge(bus, dev, func);
|
||||
if (sub_class == PCI_pci) {
|
||||
pci_bridge(bus, dev, func);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dprintf("device at %d:%d:%d => %s\n", bus, dev, func,
|
||||
decode_class(base_class, sub_class));
|
||||
}
|
||||
|
||||
/* pci_bus()
|
||||
* Scan a bus for PCI devices. For each device that's a possible
|
||||
* we get the vendor_id. If it's 0xffff then it's not a valid
|
||||
* device so we move on.
|
||||
* Valid devices then have their header_type checked to detrmine how
|
||||
* many functions we need to check. However, some devices that support
|
||||
* multiple functions have a header_type of 0 (generic) so we also check
|
||||
* for these using pci_quirk_multifunction().
|
||||
* If it's a multifunction device we scan all 8 possible functions,
|
||||
* otherwise we just probe the first one.
|
||||
*/
|
||||
static void pci_scan_bus(uint8 bus)
|
||||
{
|
||||
uint8 dev = 0, func = 0;
|
||||
uint16 vend = 0;
|
||||
|
||||
for (dev = 0; dev < 32; dev++) {
|
||||
vend = pcim->read_pci_config(bus, dev, 0, PCI_vendor_id, 2);
|
||||
if (vend != 0xffff) {
|
||||
uint16 device = pcim->read_pci_config(bus, dev, func, PCI_device_id, 2);
|
||||
uint8 type = pcim->read_pci_config(bus, dev, func, PCI_header_type, 1);
|
||||
uint8 nfunc = 8;
|
||||
|
||||
type &= PCI_header_type_mask;
|
||||
if ((type & PCI_multifunction) == 0 &&
|
||||
!pci_quirk_multifunction(vend, device))
|
||||
nfunc = 1;
|
||||
|
||||
for (func = 0; func < nfunc; func++)
|
||||
pci_device_probe(bus, dev, func);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static status_t test_me(void)
|
||||
{
|
||||
pci_info apci;
|
||||
long index = 0;
|
||||
|
||||
while (pcim->get_nth_pci_info(index++, &apci) == 0) {
|
||||
show_pci_details(&apci, pcim);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* device_modules */
|
||||
static int cfdm_std_ops(int32 op, ...)
|
||||
{
|
||||
@ -383,8 +35,6 @@ static int cfdm_std_ops(int32 op, ...)
|
||||
dprintf("config_manager: failed to load PCI module\n");
|
||||
return -1;
|
||||
}
|
||||
pci_scan_bus(0);
|
||||
test_me();
|
||||
break;
|
||||
case B_MODULE_UNINIT:
|
||||
dprintf( "config_manager: device modules: uninit\n" );
|
||||
|
@ -26,20 +26,27 @@
|
||||
/* Change to 1 to see more debugging :) */
|
||||
#define THE_FULL_MONTY 0
|
||||
|
||||
struct found_pci_device {
|
||||
struct found_pci_device *next;
|
||||
struct found_pci_device *prev;
|
||||
struct pci_device {
|
||||
struct pci_device *next;
|
||||
int type;
|
||||
pci_info *info;
|
||||
};
|
||||
|
||||
static struct found_pci_device pci_dev_list;
|
||||
|
||||
struct pci_config {
|
||||
struct pci_config *next;
|
||||
char *full_path;
|
||||
struct pci_cfg *cfg;
|
||||
struct pci_bus {
|
||||
struct pci_bus *next;
|
||||
pci_info *info;
|
||||
};
|
||||
|
||||
enum {
|
||||
PCI_DEVICE = 0,
|
||||
PCI_HOST_BUS,
|
||||
PCI_BRIDGE,
|
||||
PCI_CARDBUS
|
||||
};
|
||||
|
||||
static struct pci_device *pci_devices = NULL;
|
||||
static struct pci_bus *pci_busses = NULL;
|
||||
|
||||
static spinlock_t pci_config_lock = 0; /* lock for config space access */
|
||||
static int pci_mode = 1; /* The pci config mechanism we're using.
|
||||
* NB defaults to 1 as this is more common, but
|
||||
@ -50,10 +57,28 @@ static int bus_max_devices = 32; /* max devices that any bus can support
|
||||
* this is only 16, instead of the 32 we
|
||||
* have with pci_mode == 1
|
||||
*/
|
||||
static int pci_max_bus = 0; /* maximum bus we've found/configured */
|
||||
static region_id pci_region; /* pci_bios region we map */
|
||||
static void * pci_bios_ptr= NULL; /* virtual address of memory we map */
|
||||
static void * pci_bios_ptr = NULL; /* virtual address of memory we map */
|
||||
|
||||
static void pci_scan_bus(uint8 bus);
|
||||
static void pci_bridge(uint8 bus, uint8 dev, uint8 func);
|
||||
static void fill_basic_pci_structure(pci_info *pcii);
|
||||
static uint32 read_pci_config(uchar, uchar, uchar, uchar, uchar);
|
||||
static void write_pci_config (uchar, uchar, uchar, uchar, uchar, uint32);
|
||||
|
||||
/* XXX - move these to a header file */
|
||||
#define PCI_VENDOR_INTEL 0x8086
|
||||
|
||||
#define PCI_PRODUCT_INTEL_82371AB_ISA 0x7110 /* PIIX4 ISA */
|
||||
#define PCI_PRODUCT_INTEL_82371AB_IDE 0x7111 /* PIIX4 IDE */
|
||||
#define PCI_PRODUCT_INTEL_82371AB_USB 0x7112 /* PIIX4 USB */
|
||||
#define PCI_PRODUCT_INTEL_82371AB_PMC 0x7113 /* PIIX4 Power Management */
|
||||
|
||||
#define PCI_PRODUCT_INTEL_82443BX 0x7190
|
||||
#define PCI_PRODUCT_INTEL_82443BX_AGP 0x7191
|
||||
#define PCI_PRODUCT_INTEL_82443BX_NOAGP 0x7192
|
||||
|
||||
struct pci_config *pci_list;
|
||||
|
||||
/* Config space locking!
|
||||
* We need to make sure we only have one access at a time into the config space,
|
||||
@ -73,6 +98,176 @@ struct pci_config *pci_list;
|
||||
restore_interrupts(cpu_status); \
|
||||
}
|
||||
|
||||
/* decode_class
|
||||
* DEBUG DEBUG DEBUG
|
||||
* Provide a string that describes the class and sub-class.
|
||||
* This could/should (?) be expanded to use the api as well.
|
||||
*/
|
||||
static char *decode_class(uint8 base, uint8 sub_class)
|
||||
{
|
||||
switch(base) {
|
||||
case PCI_early:
|
||||
switch (sub_class) {
|
||||
case PCI_early_not_vga:
|
||||
return "legacy (non VGA)";
|
||||
case PCI_early_vga:
|
||||
return "legacy VGA";
|
||||
}
|
||||
case 0x01:
|
||||
switch (sub_class) {
|
||||
case PCI_scsi:
|
||||
return "mass storage controller: scsi";
|
||||
case PCI_ide:
|
||||
return "mass storage controller: ide";
|
||||
case PCI_floppy:
|
||||
return "mass storage controller: floppy";
|
||||
case PCI_ipi:
|
||||
return "mass storage controller: ipi";
|
||||
case PCI_raid:
|
||||
return "mass storage controller: raid";
|
||||
case PCI_mass_storage_other:
|
||||
return "mass storage controller: other";
|
||||
}
|
||||
case 0x02:
|
||||
switch (sub_class) {
|
||||
case PCI_ethernet:
|
||||
return "network controller: ethernet";
|
||||
case PCI_token_ring:
|
||||
return "network controller: token ring";
|
||||
case PCI_fddi:
|
||||
return "network controller: fddi";
|
||||
case PCI_atm:
|
||||
return "network controller: atm";
|
||||
case PCI_network_other:
|
||||
return "network controller: other";
|
||||
}
|
||||
case 0x03:
|
||||
switch (sub_class) {
|
||||
case PCI_vga:
|
||||
return "display controller: vga";
|
||||
case PCI_xga:
|
||||
return "display controller: xga";
|
||||
case PCI_display_other:
|
||||
return "display controller: other";
|
||||
}
|
||||
case 0x04:
|
||||
switch (sub_class) {
|
||||
case PCI_video:
|
||||
return "multimedia device: video";
|
||||
case PCI_audio:
|
||||
return "multimedia device: audio";
|
||||
case PCI_multimedia_other:
|
||||
return "multimedia device: other";
|
||||
}
|
||||
case 0x05: return "memory controller";
|
||||
case 0x06:
|
||||
switch (sub_class) {
|
||||
case PCI_host:
|
||||
return "bridge controller: host bridge";
|
||||
case PCI_isa:
|
||||
return "bridge controller: isa";
|
||||
case PCI_eisa:
|
||||
return "bridge controller: eisa";
|
||||
case PCI_microchannel:
|
||||
return "bridge controller: microchannel";
|
||||
case PCI_pci:
|
||||
return "bridge controller: PCI";
|
||||
case PCI_pcmcia:
|
||||
return "bridge controller: PC Card";
|
||||
case PCI_nubus:
|
||||
return "bridge controller: nubus";
|
||||
case PCI_cardbus:
|
||||
return "bridge controller: CardBus";
|
||||
case PCI_bridge_other:
|
||||
return "bridge controller: other";
|
||||
}
|
||||
case 0x07: return "simple comms controller";
|
||||
case 0x08: return "base system peripheral";
|
||||
case 0x09: return "input device";
|
||||
case 0x0a: return "docking station";
|
||||
case 0x0b: return "processor";
|
||||
case 0x0c:
|
||||
switch (sub_class) {
|
||||
case PCI_firewire:
|
||||
return "bus controller: IEEE1394 FireWire";
|
||||
case PCI_access:
|
||||
return "bus controller: ACCESS.bus";
|
||||
case PCI_ssa:
|
||||
return "bus controller: SSA";
|
||||
case PCI_usb:
|
||||
return "bus controller: USB";
|
||||
case PCI_fibre_channel:
|
||||
return "bus controller: fibre channel";
|
||||
}
|
||||
case 0x0d: return "wireless";
|
||||
case 0x0e: return "intelligent i/o ??";
|
||||
case 0x0f: return "satellite";
|
||||
case 0x10: return "encryption";
|
||||
case 0x11: return "signal processing";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static void show_pci_details(struct pci_info *p)
|
||||
{
|
||||
#if THE_FULL_MONTY
|
||||
uint16 ss_vend, ss_dev;
|
||||
#endif
|
||||
uint8 irq = 0;
|
||||
|
||||
if (p->header_type == PCI_header_type_generic)
|
||||
irq = p->u.h0.interrupt_line;
|
||||
else
|
||||
irq = p->u.h1.interrupt_line;
|
||||
|
||||
dprintf("0x%04x:0x%04x : ", p->vendor_id, p->device_id);
|
||||
|
||||
if (irq > 0)
|
||||
dprintf("irq %d : ", irq);
|
||||
|
||||
dprintf("location %d:%d:%d : ", p->bus, p->device, p->function);
|
||||
dprintf("class %02x:%02x:%02x", p->class_base, p->class_sub,
|
||||
p->class_api);
|
||||
dprintf(" => %s\n", decode_class(p->class_base, p->class_sub));
|
||||
|
||||
#if THE_FULL_MONTY
|
||||
dprintf("\trevision : %02x\n", p->revision);
|
||||
dprintf("\tstatus : %04x\n",
|
||||
read_pci_config(p->bus, p->device, p->function, PCI_status, 2));
|
||||
dprintf("\tcommand : %04x\n",
|
||||
read_pci_config(p->bus, p->device, p->function, PCI_command, 2));
|
||||
dprintf("\tbase address: %08x\n",
|
||||
read_pci_config(p->bus, p->device, p->function, PCI_base_registers, 4));
|
||||
|
||||
dprintf("\tline_size : %02x\n", p->line_size);
|
||||
dprintf("\theader_type : %02x\n", p->header_type);
|
||||
|
||||
if (p->header_type == PCI_header_type_generic) {
|
||||
dprintf("Header Type 0 (Generic)\n");
|
||||
dprintf("\tcardbus_cis : %08lx\n", p->u.h0.cardbus_cis);
|
||||
dprintf("\trom_base_pci : %08lx\n", p->u.h0.rom_base_pci);
|
||||
dprintf("\tinterrupt_line : %02x\n", p->u.h0.interrupt_line);
|
||||
dprintf("\tinterrupt_pin : %02x\n", p->u.h0.interrupt_pin);
|
||||
ss_vend = p->u.h0.subsystem_vendor_id;
|
||||
ss_dev = p->u.h0.subsystem_id;
|
||||
} else if (p->header_type == PCI_header_type_PCI_to_PCI_bridge) {
|
||||
dprintf("Header Type 1 (PCI-PCI bridge)\n");
|
||||
dprintf("\trom_base_pci : %08lx\n", p->u.h1.rom_base_pci);
|
||||
dprintf("\tinterrupt_line : %02x\n", p->u.h1.interrupt_line);
|
||||
dprintf("\tinterrupt_pin : %02x\n", p->u.h1.interrupt_pin);
|
||||
dprintf("\t2ndry status : %04x\n", p->u.h1.secondary_status);
|
||||
dprintf("\tprimary_bus : %d\n", p->u.h1.primary_bus);
|
||||
dprintf("\tsecondary_bus : %d\n", p->u.h1.secondary_bus);
|
||||
dprintf("\tsubordinate_bus : %d\n", p->u.h1.subordinate_bus);
|
||||
|
||||
ss_vend = p->u.h1.subsystem_vendor_id;
|
||||
ss_dev = p->u.h1.subsystem_id;
|
||||
}
|
||||
dprintf("\tsubsystem_id : %04x\n", ss_dev);
|
||||
dprintf("\tsubsystem_vendor_id : %04x\n", ss_vend);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* PCI has 2 Configuration Mechanisms. We need to decide which one the
|
||||
* PCI Host Bridge is speaking and then speak to it correctly. This is decided
|
||||
* in set_pci_mechanism() where the pci_mode value is set to the appropriate
|
||||
@ -308,6 +503,63 @@ static int pci_set_power_state(uint8 bus, uint8 dev, uint8 func, int state)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Borrowed from NetBSD.
|
||||
* Some Host bridges need to have fixes applied.
|
||||
*/
|
||||
static void fixup_host_bridge(uint8 bus, uint8 dev, uint8 func)
|
||||
{
|
||||
uint16 vendor, device;
|
||||
|
||||
vendor = read_pci_config(bus, dev, func, PCI_vendor_id, 2);
|
||||
device = read_pci_config(bus, dev, func, PCI_device_id, 2);
|
||||
|
||||
switch (vendor) {
|
||||
case PCI_VENDOR_INTEL:
|
||||
switch (device) {
|
||||
case PCI_PRODUCT_INTEL_82443BX_AGP:
|
||||
case PCI_PRODUCT_INTEL_82443BX_NOAGP: {
|
||||
/* BIOS bug workaround
|
||||
* While the datasheet indicates that the only valid setting
|
||||
* for "Idle/Pipeline DRAM Leadoff Timing (IPLDT)" is 01,
|
||||
* some BIOS's do not set these correctly, so we check and
|
||||
* correct if required.
|
||||
*/
|
||||
uint16 bcreg = read_pci_config(bus, dev, func, 0x76, 2);
|
||||
if ((bcreg & 0x0300) != 0x0100) {
|
||||
dprintf("Intel 82443BX Host Bridge: Fixing IPDLT setting\n");
|
||||
bcreg &= ~0x0300;
|
||||
bcreg |= 0x100;
|
||||
write_pci_config(bus, dev, func, 0x76, 2, bcreg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Given a vendor/device pairing, do we need to scan through
|
||||
* the entire set of funtions? normally the return will be 0,
|
||||
* implying we don't need to, but for some it will be 1 which
|
||||
* means scan all functions.
|
||||
* This function may seem overkill but it prevents scanning
|
||||
* functions we don't need to and shoudl reduce the possibility of
|
||||
* duplicates being detected.
|
||||
*/
|
||||
static int pci_quirk_multifunction(uint16 vendor, uint16 device)
|
||||
{
|
||||
switch (vendor) {
|
||||
case PCI_VENDOR_INTEL:
|
||||
switch (device) {
|
||||
case PCI_PRODUCT_INTEL_82371AB_ISA:
|
||||
case PCI_PRODUCT_INTEL_82371AB_IDE:
|
||||
case PCI_PRODUCT_INTEL_82371AB_USB:
|
||||
case PCI_PRODUCT_INTEL_82371AB_PMC:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* set_pci_mechanism()
|
||||
* Try to determine which configuration mechanism the PCI Host Bridge
|
||||
@ -499,6 +751,252 @@ static void print_pir_table(struct pir_table *tbl)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Scanning for Devices
|
||||
* ====================
|
||||
*
|
||||
* http://www.tldp.org/LDP/tlk/dd/pci.html
|
||||
*
|
||||
* Although it refers to Linux it gives a good overview of the basic
|
||||
* methodology they use for scanning PCI. We've adopted a similar
|
||||
* approach here, using the "depthwise" algorithm.
|
||||
*
|
||||
* We start by scanning a bus, which treats every device it finds the
|
||||
* same and passes them onto pci_probe_device().
|
||||
* pci_probe_device() sends pci_bridges to pci_bridge() to be setup
|
||||
* and deals with type 0 (generic) devices itself.
|
||||
*
|
||||
* NB presently we don't really cope with type 2 (Cardbus) devices
|
||||
* but will need to eventually.
|
||||
*/
|
||||
|
||||
/* pci_bridge()
|
||||
* The values passed in specify the "device" on the bus being searched
|
||||
* that has been identified as a PCI-PCI bridge. We now setup that bridge
|
||||
* and scan the bus it defines.
|
||||
* The bus is initially taken off-line, scanned and then put back on-line
|
||||
*
|
||||
* We initally set the subordinate_bus to 0xff and then adjust it to the max
|
||||
* once we've scanned the bus on the other side of the bridge. See the URL
|
||||
* above for information on why this is done.
|
||||
*/
|
||||
static void pci_bridge(uint8 bus, uint8 dev, uint8 func)
|
||||
{
|
||||
uint16 command = 0;
|
||||
uint8 mybus = bus + 1;
|
||||
struct pci_device *pcid;
|
||||
struct pci_bus *pcib;
|
||||
pci_info *pcii;
|
||||
|
||||
command = read_pci_config(bus, dev, func, PCI_command, 2);
|
||||
command &= ~ 0x03;
|
||||
write_pci_config(bus, dev, func, PCI_command, 2, command);
|
||||
|
||||
write_pci_config(bus, dev, func, PCI_primary_bus, 1, bus);
|
||||
write_pci_config(bus, dev, func, PCI_secondary_bus, 1, mybus);
|
||||
write_pci_config(bus, dev, func, PCI_subordinate_bus, 1, 0xff);
|
||||
pci_max_bus = bus + 1;
|
||||
|
||||
dprintf("PCI-PCI bridge at %d:%d:%d configured as bus %d\n", bus, dev, func, mybus);
|
||||
pci_scan_bus(mybus);
|
||||
|
||||
write_pci_config(bus, dev, func, PCI_subordinate_bus, 1, pci_max_bus);
|
||||
|
||||
pcii = (pci_info*)kmalloc(sizeof(pci_info));
|
||||
if (!pcii)
|
||||
return;
|
||||
pcid = (struct pci_device*)kmalloc(sizeof(struct pci_device));
|
||||
if (!pcid) {
|
||||
kfree(pcii);
|
||||
return;
|
||||
}
|
||||
pcib = (struct pci_bus *)kmalloc(sizeof(struct pci_bus));
|
||||
if (!pcib) {
|
||||
kfree(pcii);
|
||||
kfree(pcid);
|
||||
return;
|
||||
}
|
||||
|
||||
pcid->info = pcii;
|
||||
pcid->type = PCI_BRIDGE;
|
||||
pcib->info = pcii;
|
||||
pcii->bus = bus;
|
||||
pcii->device = dev;
|
||||
pcii->function = func;
|
||||
|
||||
fill_basic_pci_structure(pcii);
|
||||
|
||||
pcii->u.h1.rom_base_pci = read_pci_config(bus, dev, func, PCI_bridge_rom_base, 4);
|
||||
pcii->u.h1.primary_bus = read_pci_config(bus, dev, func, PCI_primary_bus, 1);
|
||||
pcii->u.h1.secondary_bus = read_pci_config(bus, dev, func, PCI_secondary_bus, 1);
|
||||
pcii->u.h1.secondary_latency = read_pci_config(bus, dev, func, PCI_secondary_latency, 1);
|
||||
pcii->u.h1.secondary_status = read_pci_config(bus, dev, func, PCI_secondary_status, 2);
|
||||
pcii->u.h1.subordinate_bus = read_pci_config(bus, dev, func, PCI_subordinate_bus, 1);
|
||||
pcii->u.h1.memory_base = read_pci_config(bus, dev, func, PCI_memory_base, 2);
|
||||
pcii->u.h1.memory_limit = read_pci_config(bus, dev, func, PCI_memory_limit, 2);
|
||||
pcii->u.h1.prefetchable_memory_base = read_pci_config(bus, dev, func, PCI_prefetchable_memory_base, 2);
|
||||
pcii->u.h1.prefetchable_memory_limit = read_pci_config(bus, dev, func, PCI_prefetchable_memory_limit, 2);
|
||||
pcii->u.h1.bridge_control = read_pci_config(bus, dev, func, PCI_bridge_control, 1);
|
||||
pcii->u.h1.subsystem_vendor_id = read_pci_config(bus, dev, func, PCI_sub_vendor_id_1, 2);
|
||||
pcii->u.h1.subsystem_id = read_pci_config(bus, dev, func, PCI_sub_device_id_1, 2);
|
||||
pcii->u.h1.interrupt_line = read_pci_config(bus, dev, func, PCI_interrupt_line, 1);
|
||||
pcii->u.h1.interrupt_pin = read_pci_config(bus, dev, func, PCI_interrupt_pin, 1) & PCI_pin_mask;
|
||||
|
||||
{
|
||||
struct pci_device *pd = pci_devices;
|
||||
while (pd && pd->next)
|
||||
pd = pd->next;
|
||||
|
||||
if (pd)
|
||||
pd->next = pcid;
|
||||
else
|
||||
pci_devices = pcid;
|
||||
}
|
||||
{
|
||||
struct pci_bus *pb = pci_busses;
|
||||
while (pb && pb->next)
|
||||
pb = pb->next;
|
||||
|
||||
if (pb)
|
||||
pb->next = pcib;
|
||||
else
|
||||
pci_busses = pcib;
|
||||
}
|
||||
|
||||
command |= 0x03;
|
||||
write_pci_config(mybus, dev, func, PCI_command, 2, command);
|
||||
|
||||
show_pci_details(pcii);
|
||||
return;
|
||||
}
|
||||
|
||||
/* This is a very, very brief 2 liner for a device... */
|
||||
|
||||
static void debug_show_device(pci_info *pcii)
|
||||
{
|
||||
dprintf("device at %d:%d:%d => %s\n", pcii->bus, pcii->device,
|
||||
pcii->function,
|
||||
decode_class(pcii->class_base, pcii->class_sub));
|
||||
dprintf("Capabilities: ");
|
||||
if (pci_get_capability(pcii->bus, pcii->device, pcii->function, PCI_cap_id_agp, NULL))
|
||||
dprintf("AGP ");
|
||||
if (pci_get_capability(pcii->bus, pcii->device, pcii->function, PCI_cap_id_pm, NULL))
|
||||
dprintf("Pwr Mgmt ");
|
||||
if (pci_get_capability(pcii->bus, pcii->device, pcii->function, PCI_cap_id_vpd, NULL))
|
||||
dprintf("VPD ");
|
||||
if (pci_get_capability(pcii->bus, pcii->device, pcii->function, PCI_cap_id_slotid, NULL))
|
||||
dprintf("slotID ");
|
||||
if (pci_get_capability(pcii->bus, pcii->device, pcii->function, PCI_cap_id_msi, NULL))
|
||||
dprintf("MSI ");
|
||||
if (pci_get_capability(pcii->bus, pcii->device, pcii->function, PCI_cap_id_hotplug, NULL))
|
||||
dprintf("hotplug ");
|
||||
dprintf("\n");
|
||||
}
|
||||
|
||||
static void pci_device_probe(uint8 bus, uint8 dev, uint8 func)
|
||||
{
|
||||
uint8 base_class, sub_class;
|
||||
uint8 type;
|
||||
pci_info *pcii;
|
||||
struct pci_device *pcid;
|
||||
|
||||
if (func > 0) {
|
||||
uint16 vend = read_pci_config(bus, dev, func, PCI_vendor_id, 2);
|
||||
if (vend == 0xffff)
|
||||
return;
|
||||
}
|
||||
|
||||
type = read_pci_config(bus, dev, func, PCI_header_type, 1);
|
||||
type &= PCI_header_type_mask;
|
||||
base_class = read_pci_config(bus, dev, func, PCI_class_base, 1);
|
||||
sub_class = read_pci_config(bus, dev, func, PCI_class_sub, 1);
|
||||
|
||||
if (base_class == PCI_bridge) {
|
||||
if (sub_class == PCI_host)
|
||||
fixup_host_bridge(bus, dev, func);
|
||||
if (sub_class == PCI_pci) {
|
||||
pci_bridge(bus, dev, func);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* If we get here then it's not a bridge, so we add it... */
|
||||
pcii = (pci_info*)kmalloc(sizeof(pci_info));
|
||||
if (!pcii)
|
||||
return;
|
||||
pcid = (struct pci_device*)kmalloc(sizeof(struct pci_device));
|
||||
if (!pcid) {
|
||||
kfree(pcii);
|
||||
return;
|
||||
}
|
||||
|
||||
pcid->info = pcii;
|
||||
pcid->type = PCI_DEVICE;
|
||||
pcii->bus = bus;
|
||||
pcii->device = dev;
|
||||
pcii->function = func;
|
||||
|
||||
fill_basic_pci_structure(pcii);
|
||||
|
||||
if (pcii->class_base == PCI_bridge && pcii->class_sub == PCI_host)
|
||||
pcid->type = PCI_HOST_BUS;
|
||||
|
||||
pcii->u.h0.cardbus_cis = read_pci_config(bus, dev, func, PCI_cardbus_cis, 4);
|
||||
pcii->u.h0.subsystem_id = read_pci_config(bus, dev, func, PCI_subsystem_id, 2);
|
||||
pcii->u.h0.subsystem_vendor_id = read_pci_config(bus, dev, func, PCI_subsystem_vendor_id, 2);
|
||||
pcii->u.h0.rom_base_pci = read_pci_config(bus, dev, func, PCI_rom_base, 4);
|
||||
pcii->u.h0.interrupt_line = read_pci_config(bus, dev, func, PCI_interrupt_line, 1);
|
||||
pcii->u.h0.interrupt_pin = read_pci_config(bus, dev, func, PCI_interrupt_pin, 1) & PCI_pin_mask;
|
||||
|
||||
/* now add to list (at end) */
|
||||
{
|
||||
struct pci_device *pd = pci_devices;
|
||||
while (pd && pd->next)
|
||||
pd = pd->next;
|
||||
|
||||
if (pd)
|
||||
pd->next = pcid;
|
||||
else
|
||||
pci_devices = pcid;
|
||||
}
|
||||
pci_set_power_state(bus, dev, func, PCI_pm_state_d0);
|
||||
|
||||
debug_show_device(pcii);
|
||||
}
|
||||
|
||||
/* pci_bus()
|
||||
* Scan a bus for PCI devices. For each device that's a possible
|
||||
* we get the vendor_id. If it's 0xffff then it's not a valid
|
||||
* device so we move on.
|
||||
* Valid devices then have their header_type checked to detrmine how
|
||||
* many functions we need to check. However, some devices that support
|
||||
* multiple functions have a header_type of 0 (generic) so we also check
|
||||
* for these using pci_quirk_multifunction().
|
||||
* If it's a multifunction device we scan all 8 possible functions,
|
||||
* otherwise we just probe the first one.
|
||||
*/
|
||||
static void pci_scan_bus(uint8 bus)
|
||||
{
|
||||
uint8 dev = 0, func = 0;
|
||||
uint16 vend = 0;
|
||||
|
||||
for (dev = 0; dev < 32; dev++) {
|
||||
vend = read_pci_config(bus, dev, 0, PCI_vendor_id, 2);
|
||||
if (vend != 0xffff) {
|
||||
uint16 device = read_pci_config(bus, dev, func, PCI_device_id, 2);
|
||||
uint8 type = read_pci_config(bus, dev, func, PCI_header_type, 1);
|
||||
uint8 nfunc = 8;
|
||||
|
||||
type &= PCI_header_type_mask;
|
||||
|
||||
if ((type & PCI_multifunction) == 0 &&
|
||||
!pci_quirk_multifunction(vend, device))
|
||||
nfunc = 1;
|
||||
|
||||
for (func = 0; func < nfunc; func++)
|
||||
pci_device_probe(bus, dev, func);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void scan_pci(void)
|
||||
{
|
||||
int bus, dev, func;
|
||||
@ -512,7 +1010,6 @@ static void scan_pci(void)
|
||||
|
||||
for (func = 0; func < 8; func++) {
|
||||
pci_info *pcii = NULL;
|
||||
struct found_pci_device *npcid = NULL;
|
||||
uint16 vendor_id = read_pci_config(bus, dev, func, 0, 2);
|
||||
uint16 device_id;
|
||||
uint8 offset;
|
||||
@ -546,11 +1043,6 @@ static void scan_pci(void)
|
||||
dprintf("Failed to get memory for a pic_info structure in scan_pci\n");
|
||||
return;
|
||||
}
|
||||
if ((npcid = (struct found_pci_device*)kmalloc(sizeof(struct found_pci_device))) == NULL) {
|
||||
kfree(pcii);
|
||||
dprintf("scan_pci: failed to kmalloc memory for found_pci_device structure\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pci_get_capability(bus, dev, func, PCI_cap_id_agp, &offset))
|
||||
dprintf("Device @ %d:%d:%d has AGP capability\n", bus, dev, func);
|
||||
@ -570,19 +1062,26 @@ static void scan_pci(void)
|
||||
|
||||
pcii->header_type = read_pci_config(bus, dev, func, PCI_header_type, 1);
|
||||
pcii->header_type &= PCI_header_type_mask;
|
||||
|
||||
npcid->info = pcii;
|
||||
/* Add the device to the list */
|
||||
insque(npcid, &pci_dev_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_pci_structure(pci_info *pcii)
|
||||
static void fill_basic_pci_structure(pci_info *pcii)
|
||||
{
|
||||
uint8 bus = pcii->bus, dev = pcii->device, func = pcii->function;
|
||||
uint8 int_line = 0, int_pin = 0;
|
||||
|
||||
pcii->vendor_id = read_pci_config(bus, dev, func, PCI_vendor_id, 2);
|
||||
pcii->device_id = read_pci_config(bus, dev, func, PCI_device_id, 2);
|
||||
|
||||
pcii->revision = read_pci_config(bus, dev, func, PCI_revision, 1);
|
||||
pcii->class_api = read_pci_config(bus, dev, func, PCI_class_api, 1);
|
||||
pcii->class_sub = read_pci_config(bus, dev, func, PCI_class_sub, 1);
|
||||
pcii->class_base = read_pci_config(bus, dev, func, PCI_class_base, 1);
|
||||
|
||||
pcii->header_type = read_pci_config(bus, dev, func, PCI_header_type, 1);
|
||||
pcii->header_type &= PCI_header_type_mask;
|
||||
|
||||
pcii->latency = read_pci_config(bus, dev, func, PCI_latency, 1);
|
||||
pcii->bist = read_pci_config(bus, dev, func, PCI_bist, 1);
|
||||
@ -591,43 +1090,6 @@ static void fill_pci_structure(pci_info *pcii)
|
||||
int_line = read_pci_config(bus, dev, func, PCI_interrupt_line, 1);
|
||||
int_pin = read_pci_config(bus, dev, func, PCI_interrupt_pin, 1);
|
||||
int_pin &= PCI_pin_mask;
|
||||
|
||||
/* device type specific headers based on header_type declared */
|
||||
if (pcii->header_type == PCI_header_type_generic) {
|
||||
/* header type 0 */
|
||||
pcii->u.h0.cardbus_cis = read_pci_config(bus, dev, func, PCI_cardbus_cis, 4);
|
||||
pcii->u.h0.subsystem_id = read_pci_config(bus, dev, func, PCI_subsystem_id, 2);
|
||||
pcii->u.h0.subsystem_vendor_id = read_pci_config(bus, dev, func, PCI_subsystem_vendor_id, 2);
|
||||
pcii->u.h0.rom_base_pci = read_pci_config(bus, dev, func, PCI_rom_base, 4);
|
||||
pcii->u.h0.interrupt_line = int_line;
|
||||
pcii->u.h0.interrupt_pin = int_pin;
|
||||
} else if (pcii->header_type == PCI_header_type_PCI_to_PCI_bridge) {
|
||||
/* header_type 1 */
|
||||
/* PCI-PCI bridge - may be used for AGP */
|
||||
pcii->u.h1.rom_base_pci = read_pci_config(bus, dev, func, PCI_bridge_rom_base, 4);
|
||||
pcii->u.h1.primary_bus = read_pci_config(bus, dev, func, PCI_primary_bus, 1);
|
||||
pcii->u.h1.secondary_bus = read_pci_config(bus, dev, func, PCI_secondary_bus, 1);
|
||||
pcii->u.h1.secondary_latency = read_pci_config(bus, dev, func, PCI_secondary_latency, 1);
|
||||
pcii->u.h1.secondary_status = read_pci_config(bus, dev, func, PCI_secondary_status, 2);
|
||||
pcii->u.h1.subordinate_bus = read_pci_config(bus, dev, func, PCI_subordinate_bus, 1);
|
||||
pcii->u.h1.memory_base = read_pci_config(bus, dev, func, PCI_memory_base, 2);
|
||||
pcii->u.h1.memory_limit = read_pci_config(bus, dev, func, PCI_memory_limit, 2);
|
||||
pcii->u.h1.prefetchable_memory_base = read_pci_config(bus, dev, func, PCI_prefetchable_memory_base, 2);
|
||||
pcii->u.h1.prefetchable_memory_limit = read_pci_config(bus, dev, func, PCI_prefetchable_memory_limit, 2);
|
||||
pcii->u.h1.bridge_control = read_pci_config(bus, dev, func, PCI_bridge_control, 1);
|
||||
pcii->u.h1.subsystem_vendor_id = read_pci_config(bus, dev, func, PCI_sub_vendor_id_1, 2);
|
||||
pcii->u.h1.subsystem_id = read_pci_config(bus, dev, func, PCI_sub_device_id_1, 2);
|
||||
pcii->u.h1.interrupt_line = int_line;
|
||||
pcii->u.h1.interrupt_pin = int_pin;
|
||||
|
||||
} else if (pcii->header_type == PCI_header_type_cardbus) {
|
||||
pcii->u.h2.subsystem_vendor_id = read_pci_config(bus, dev, func, PCI_sub_vendor_id_2, 2);
|
||||
pcii->u.h2.subsystem_id = read_pci_config(bus, dev, func, PCI_sub_device_id_2, 2);
|
||||
|
||||
}else if (pcii->header_type == PCI_multifunction) {
|
||||
dprintf("PCI: multifunction device detected\n");
|
||||
/* ??? */
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX - check the return values from this function. */
|
||||
@ -639,7 +1101,7 @@ static long get_nth_pci_info(long index, pci_info *copyto)
|
||||
* XXX - see discussion below.
|
||||
*/
|
||||
long iter = index;
|
||||
struct found_pci_device *fpd = pci_dev_list.prev;
|
||||
struct pci_device *pd = pci_devices;
|
||||
|
||||
/* iterate through the list until we have iter == 0
|
||||
* NB we go in "reverse" as the devices are inserted into the
|
||||
@ -652,8 +1114,8 @@ static long get_nth_pci_info(long index, pci_info *copyto)
|
||||
* XXX - if we do decide to reverse the order we need to be very
|
||||
* careful about which function # gets found first and returned.
|
||||
*/
|
||||
while (iter-- > 0 && fpd && fpd != &pci_dev_list)
|
||||
fpd = fpd->prev;
|
||||
while (iter-- > 0 && pd)
|
||||
pd = pd->next;
|
||||
|
||||
/* 2 cases we bail here.
|
||||
* 1) we don't have enough devices to fulfill the request
|
||||
@ -661,12 +1123,10 @@ static long get_nth_pci_info(long index, pci_info *copyto)
|
||||
* 2) The found_device_structure has a NULL pointer for
|
||||
* info, which would cause a segfault when we try to memcpy!
|
||||
*/
|
||||
if (iter > 0 || !fpd->info)
|
||||
if (iter > 0 || !pd->info)
|
||||
return B_DEV_ID_ERROR;
|
||||
|
||||
fill_pci_structure(fpd->info);
|
||||
|
||||
memcpy(copyto, fpd->info, sizeof(pci_info));
|
||||
memcpy(copyto, pd->info, sizeof(pci_info));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -701,24 +1161,32 @@ static void pci_write_io_32(int mapped_io_addr, uint32 value)
|
||||
out32(value, mapped_io_addr);
|
||||
}
|
||||
|
||||
/* pci_module_init
|
||||
* This is where we start all the PCI work, or not as the case may be.
|
||||
* We start by trying to detect and set the correct configuration mechanism
|
||||
* to use. We don't handle PCI BIOS's as that method seems to be falling out
|
||||
* of fashion and is Intel specific.
|
||||
*
|
||||
* Next we try to check if we have working PCI on this machine. check_pci()
|
||||
* isn't the smartest routine as it essentially just looks for a Host-PCI
|
||||
* bridge, but it will show us if we can continue.
|
||||
* NB Until this has been tested with a wider audience we don't consider
|
||||
* success/failure here but spew a large debug message and try to continue.
|
||||
* XXX - once we're happy with check_pci() make failing a criminal offense!
|
||||
*
|
||||
* Next we check to see if we can find a PIR table.
|
||||
* NB This is Intel specific and currently included here as a test.
|
||||
*
|
||||
* Finally we scan for devices starting at bus 0.
|
||||
*/
|
||||
static void pci_module_init(void)
|
||||
{
|
||||
struct pir_table *pirt = NULL;
|
||||
|
||||
/* init the double linked list */
|
||||
pci_dev_list.next = pci_dev_list.prev = &pci_dev_list;
|
||||
|
||||
/* Determine how we communicate with the PCI Host Bridge */
|
||||
if (set_pci_mechanism() == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check PCI is valid and we can use it.
|
||||
* Presently we don't do anything with this other than run it and
|
||||
* inform the user if we pass/fail. If we fail we print a big message
|
||||
* asking the user to get in touch to let us know about their system so
|
||||
* we can refine the test.
|
||||
*/
|
||||
check_pci();
|
||||
|
||||
pci_region = vm_map_physical_memory(vm_get_kernel_aspace_id(),
|
||||
@ -728,7 +1196,6 @@ static void pci_module_init(void)
|
||||
LOCK_RO | LOCK_KERNEL,
|
||||
(addr)0xf0000);
|
||||
|
||||
|
||||
pirt = find_pir_table();
|
||||
if (pirt) {
|
||||
dprintf("PCI IRQ Routing table found\n");
|
||||
@ -737,10 +1204,13 @@ static void pci_module_init(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Get our initial list of devices */
|
||||
scan_pci();
|
||||
pci_scan_bus(0);
|
||||
}
|
||||
|
||||
/* pci_module_uninit
|
||||
* Finish the module by releasing the memory we grabbed for
|
||||
* the pci_bios :)
|
||||
*/
|
||||
static void pci_module_uninit(void)
|
||||
{
|
||||
vm_delete_region(vm_get_kernel_aspace_id(), pci_region);
|
||||
|
Loading…
Reference in New Issue
Block a user