* probe.c - PCI detection and setup code
*/
+#include <linux/kernel.h>
+#include <linux/delay.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/cpumask.h>
-
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
+#include "pci.h"
#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */
#define CARDBUS_RESERVE_BUSNR 3
LIST_HEAD(pci_devices);
+#ifdef HAVE_PCI_LEGACY
+/**
+ * pci_create_legacy_files - create legacy I/O port and memory files
+ * @b: bus to create files under
+ *
+ * Some platforms allow access to legacy I/O port and ISA memory space on
+ * a per-bus basis. This routine creates the files and ties them into
+ * their associated read, write and mmap files from pci-sysfs.c
+ */
+static void pci_create_legacy_files(struct pci_bus *b)
+{
+ b->legacy_io = kmalloc(sizeof(struct bin_attribute) * 2,
+ GFP_ATOMIC);
+ if (b->legacy_io) {
+ memset(b->legacy_io, 0, sizeof(struct bin_attribute) * 2);
+ b->legacy_io->attr.name = "legacy_io";
+ b->legacy_io->size = 0xffff;
+ b->legacy_io->attr.mode = S_IRUSR | S_IWUSR;
+ b->legacy_io->attr.owner = THIS_MODULE;
+ b->legacy_io->read = pci_read_legacy_io;
+ b->legacy_io->write = pci_write_legacy_io;
+ class_device_create_bin_file(&b->class_dev, b->legacy_io);
+
+ /* Allocated above after the legacy_io struct */
+ b->legacy_mem = b->legacy_io + 1;
+ b->legacy_mem->attr.name = "legacy_mem";
+ b->legacy_mem->size = 1024*1024;
+ b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR;
+ b->legacy_mem->attr.owner = THIS_MODULE;
+ b->legacy_mem->mmap = pci_mmap_legacy_mem;
+ class_device_create_bin_file(&b->class_dev, b->legacy_mem);
+ }
+}
+
+void pci_remove_legacy_files(struct pci_bus *b)
+{
+ if (b->legacy_io) {
+ class_device_remove_bin_file(&b->class_dev, b->legacy_io);
+ class_device_remove_bin_file(&b->class_dev, b->legacy_mem);
+ kfree(b->legacy_io); /* both are allocated here */
+ }
+}
+#else /* !HAVE_PCI_LEGACY */
+static inline void pci_create_legacy_files(struct pci_bus *bus) { return; }
+void pci_remove_legacy_files(struct pci_bus *bus) { return; }
+#endif /* HAVE_PCI_LEGACY */
+
+/*
+ * PCI Bus Class Devices
+ */
+static ssize_t pci_bus_show_cpuaffinity(struct class_device *class_dev, char *buf)
+{
+ cpumask_t cpumask = pcibus_to_cpumask(to_pci_bus(class_dev));
+ int ret;
+
+ ret = cpumask_scnprintf(buf, PAGE_SIZE, cpumask);
+ if (ret < PAGE_SIZE)
+ buf[ret++] = '\n';
+ return ret;
+}
+CLASS_DEVICE_ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpuaffinity, NULL);
+
/*
* PCI Bus Class
*/
static void release_pcibus_dev(struct class_device *class_dev)
{
struct pci_bus *pci_bus = to_pci_bus(class_dev);
+
if (pci_bus->bridge)
put_device(pci_bus->bridge);
kfree(pci_bus);
}
postcore_initcall(pcibus_class_init);
-/*
- * PCI Bus Class Devices
- */
-static ssize_t pci_bus_show_cpuaffinity(struct class_device *class_dev, char *buf)
-{
- cpumask_t cpumask = pcibus_to_cpumask((to_pci_bus(class_dev))->number);
- int ret;
-
- ret = cpumask_scnprintf(buf, PAGE_SIZE, cpumask);
- if (ret < PAGE_SIZE)
- buf[ret++] = '\n';
- return ret;
-}
-static CLASS_DEVICE_ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpuaffinity, NULL);
-
/*
* Translate the low bits of the PCI base
* to the resource type
/*
* Find the extent of a PCI decode..
*/
-static u32 pci_size(u32 base, u32 maxbase, unsigned long mask)
+static u32 pci_size(u32 base, u32 maxbase, u32 mask)
{
u32 size = mask & maxbase; /* Find the significant bits */
if (!size)
return child;
}
+static void pci_enable_crs(struct pci_dev *dev)
+{
+ u16 cap, rpctl;
+ int rpcap = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (!rpcap)
+ return;
+
+ pci_read_config_word(dev, rpcap + PCI_CAP_FLAGS, &cap);
+ if (((cap & PCI_EXP_FLAGS_TYPE) >> 4) != PCI_EXP_TYPE_ROOT_PORT)
+ return;
+
+ pci_read_config_word(dev, rpcap + PCI_EXP_RTCTL, &rpctl);
+ rpctl |= PCI_EXP_RTCTL_CRSSVE;
+ pci_write_config_word(dev, rpcap + PCI_EXP_RTCTL, rpctl);
+}
+
unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus);
/*
pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
- DBG("Scanning behind PCI bridge %s, config %06x, pass %d\n",
- pci_name(dev), buses & 0xffffff, pass);
+ pr_debug("PCI: Scanning behind PCI bridge %s, config %06x, pass %d\n",
+ pci_name(dev), buses & 0xffffff, pass);
/* Disable MasterAbortMode during probing to avoid reporting
of bus errors (in some architectures) */
pci_write_config_word(dev, PCI_BRIDGE_CONTROL,
bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT);
+ pci_enable_crs(dev);
+
if ((buses & 0xffff00) && !pcibios_assign_all_busses() && !is_cardbus) {
unsigned int cmax, busnr;
/*
if (pass)
return max;
busnr = (buses >> 8) & 0xFF;
+
+ /*
+ * If we already got to this bus through a different bridge,
+ * ignore it. This can happen with the i450NX chipset.
+ */
+ if (pci_find_bus(pci_domain_nr(bus), busnr)) {
+ printk(KERN_INFO "PCI: Bus %04x:%02x already known\n",
+ pci_domain_nr(bus), busnr);
+ return max;
+ }
+
child = pci_alloc_child_bus(bus, dev, busnr);
if (!child)
return max;
{
u32 class;
- dev->slot_name = dev->dev.bus_id;
sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(dev->bus),
dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
dev->class = class;
class >>= 8;
- DBG("Found %02x:%02x [%04x/%04x] %06x %02x\n", dev->bus->number,
- dev->devfn, dev->vendor, dev->device, class, dev->hdr_type);
+ pr_debug("PCI: Found %s [%04x/%04x] %06x %02x\n", pci_name(dev),
+ dev->vendor, dev->device, class, dev->hdr_type);
/* "Unknown power state" */
dev->current_state = 4;
/* Early fixups, before probing the BARs */
pci_fixup_device(pci_fixup_early, dev);
+ class = dev->class >> 8;
switch (dev->hdr_type) { /* header type */
case PCI_HEADER_TYPE_NORMAL: /* standard header */
struct pci_dev *dev;
u32 l;
u8 hdr_type;
-
- if (pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type))
- return NULL;
+ int delay = 1;
if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l))
return NULL;
l == 0x0000ffff || l == 0xffff0000)
return NULL;
+ /* Configuration request Retry Status */
+ while (l == 0xffff0001) {
+ msleep(delay);
+ delay *= 2;
+ if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l))
+ return NULL;
+ /* Card hasn't responded in 60 seconds? Must be stuck. */
+ if (delay > 60 * 1000) {
+ printk(KERN_WARNING "Device %04x:%02x:%02x.%d not "
+ "responding\n", pci_domain_nr(bus),
+ bus->number, PCI_SLOT(devfn),
+ PCI_FUNC(devfn));
+ return NULL;
+ }
+ }
+
+ if (pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type))
+ return NULL;
+
dev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
if (!dev)
return NULL;
unsigned int devfn, pass, max = bus->secondary;
struct pci_dev *dev;
- DBG("Scanning bus %02x\n", bus->number);
+ pr_debug("PCI: Scanning bus %04x:%02x\n", pci_domain_nr(bus), bus->number);
/* Go find them, Rover! */
for (devfn = 0; devfn < 0x100; devfn += 8)
* After performing arch-dependent fixup of the bus, look behind
* all PCI-to-PCI bridges on this bus.
*/
- DBG("Fixups for bus %02x\n", bus->number);
+ pr_debug("PCI: Fixups for bus %04x:%02x\n", pci_domain_nr(bus), bus->number);
pcibios_fixup_bus(bus);
for (pass=0; pass < 2; pass++)
list_for_each_entry(dev, &bus->devices, bus_list) {
*
* Return how far we've got finding sub-buses.
*/
- DBG("Bus scan for %02x returning with max=%02x\n", bus->number, max);
+ pr_debug("PCI: Bus scan for %04x:%02x returning with max=%02x\n",
+ pci_domain_nr(bus), bus->number, max);
return max;
}
if (pci_find_bus(pci_domain_nr(b), bus)) {
/* If we already got to this bus through a different bridge, ignore it */
- DBG("PCI: Bus %02x already known\n", bus);
+ pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus);
goto err_out;
}
list_add_tail(&b->node, &pci_root_buses);
if (error)
goto class_dev_create_file_err;
+ /* Create legacy_io and legacy_mem files for this bus */
+ pci_create_legacy_files(b);
+
error = sysfs_create_link(&b->class_dev.kobj, &b->bridge->kobj, "bridge");
if (error)
goto sys_create_link_err;