* Re: [CFT] PCI probing for cardbus (1/5)
2003-03-05 0:36 [CFT] PCI probing for cardbus Russell King
@ 2003-03-05 0:39 ` Russell King
2003-03-05 0:39 ` [CFT] PCI probing for cardbus (2/5) Russell King
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Russell King @ 2003-03-05 0:39 UTC (permalink / raw)
To: Linux Kernel List
diff -uN orig/drivers/pci/Makefile linux/drivers/pci/Makefile
--- orig/drivers/pci/Makefile Tue Feb 25 10:57:49 2003
+++ linux/drivers/pci/Makefile Sat Mar 1 15:41:20 2003
@@ -2,7 +2,7 @@
# Makefile for the PCI bus specific drivers.
#
-obj-y += access.o probe.o pci.o pool.o quirks.o \
+obj-y += access.o bus.o probe.o pci.o pool.o quirks.o \
names.o pci-driver.o search.o hotplug.o \
pci-sysfs.o
obj-$(CONFIG_PM) += power.o
diff -uN orig/drivers/pci/bus.c linux/drivers/pci/bus.c
--- orig/drivers/pci/bus.c Thu Jan 1 01:00:00 1970
+++ linux/drivers/pci/bus.c Sat Mar 1 16:36:43 2003
@@ -0,0 +1,81 @@
+/*
+ * drivers/pci/bus.c
+ *
+ * From setup-res.c, by:
+ * Dave Rusling (david.rusling@reo.mts.dec.com)
+ * David Mosberger (davidm@cs.arizona.edu)
+ * David Miller (davem@redhat.com)
+ * Ivan Kokshaysky (ink@jurassic.park.msu.ru)
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+
+/**
+ * pci_bus_alloc_resource - allocate a resource from a parent bus
+ * @bus: PCI bus
+ * @res: resource to allocate
+ * @size: size of resource to allocate
+ * @align: alignment of resource to allocate
+ * @min: minimum /proc/iomem address to allocate
+ * @type_mask: IORESOURCE_* type flags
+ * @alignf: resource alignment function
+ * @alignf_data: data argument for resource alignment function
+ *
+ * Given the PCI bus a device resides on, the size, minimum address,
+ * alignment and type, try to find an acceptable resource allocation
+ * for a specific device resource.
+ */
+int
+pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
+ unsigned long size, unsigned long align, unsigned long min,
+ unsigned int type_mask,
+ void (*alignf)(void *, struct resource *,
+ unsigned long, unsigned long),
+ void *alignf_data)
+{
+ int i, ret = -ENOMEM;
+
+ type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
+
+ for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
+ struct resource *r = bus->resource[i];
+ if (!r)
+ continue;
+
+ /* type_mask must match */
+ if ((res->flags ^ r->flags) & type_mask)
+ continue;
+
+ /* We cannot allocate a non-prefetching resource
+ from a pre-fetching area */
+ if ((r->flags & IORESOURCE_PREFETCH) &&
+ !(res->flags & IORESOURCE_PREFETCH))
+ continue;
+
+ /* Ok, try it out.. */
+ ret = allocate_resource(r, res, size, min, -1, align,
+ alignf, alignf_data);
+ if (ret == 0)
+ break;
+ }
+ return ret;
+}
+
+void pci_enable_bridges(struct pci_bus *bus)
+{
+ struct pci_dev *dev;
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ if (dev->subordinate) {
+ pci_enable_device(dev);
+ pci_set_master(dev);
+ pci_enable_bridges(dev->subordinate);
+ }
+ }
+}
+
+EXPORT_SYMBOL(pci_bus_alloc_resource);
+EXPORT_SYMBOL(pci_enable_bridges);
diff -uN orig/drivers/pci/setup-res.c linux/drivers/pci/setup-res.c
--- orig/drivers/pci/setup-res.c Sat Dec 28 17:07:35 2002
+++ linux/drivers/pci/setup-res.c Sat Mar 1 10:11:51 2003
@@ -55,84 +55,47 @@
return err;
}
-/*
- * Given the PCI bus a device resides on, try to
- * find an acceptable resource allocation for a
- * specific device resource..
- */
-static int pci_assign_bus_resource(const struct pci_bus *bus,
- struct pci_dev *dev,
- struct resource *res,
- unsigned long size,
- unsigned long min,
- unsigned int type_mask,
- int resno)
+int pci_assign_resource(struct pci_dev *dev, int resno)
{
- unsigned long align;
- int i;
-
- type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
- for (i = 0 ; i < PCI_BUS_NUM_RESOURCES; i++) {
- struct resource *r = bus->resource[i];
- if (!r)
- continue;
-
- /* type_mask must match */
- if ((res->flags ^ r->flags) & type_mask)
- continue;
-
- /* We cannot allocate a non-prefetching resource
- from a pre-fetching area */
- if ((r->flags & IORESOURCE_PREFETCH) &&
- !(res->flags & IORESOURCE_PREFETCH))
- continue;
-
- /* The bridge resources are special, as their
- size != alignment. Sizing routines return
- required alignment in the "start" field. */
- align = (resno < PCI_BRIDGE_RESOURCES) ? size : res->start;
-
- /* Ok, try it out.. */
- if (allocate_resource(r, res, size, min, -1, align,
- pcibios_align_resource, dev) < 0)
- continue;
-
- /* Update PCI config space. */
- pcibios_update_resource(dev, r, res, resno);
- return 0;
- }
- return -EBUSY;
-}
-
-int
-pci_assign_resource(struct pci_dev *dev, int i)
-{
- const struct pci_bus *bus = dev->bus;
- struct resource *res = dev->resource + i;
- unsigned long size, min;
+ struct pci_bus *bus = dev->bus;
+ struct resource *res = dev->resource + resno;
+ unsigned long size, min, align;
+ int ret;
size = res->end - res->start + 1;
min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
+ /* The bridge resources are special, as their
+ size != alignment. Sizing routines return
+ required alignment in the "start" field. */
+ align = (resno < PCI_BRIDGE_RESOURCES) ? size : res->start;
/* First, try exact prefetching match.. */
- if (pci_assign_bus_resource(bus, dev, res, size, min, IORESOURCE_PREFETCH, i) < 0) {
+ ret = pci_bus_alloc_resource(bus, res, size, align, min,
+ IORESOURCE_PREFETCH,
+ pcibios_align_resource, dev);
+
+ if (ret < 0 && (res->flags & IORESOURCE_PREFETCH)) {
/*
* That failed.
*
* But a prefetching area can handle a non-prefetching
* window (it will just not perform as well).
*/
- if (!(res->flags & IORESOURCE_PREFETCH) || pci_assign_bus_resource(bus, dev, res, size, min, 0, i) < 0) {
- printk(KERN_ERR "PCI: Failed to allocate resource %d(%lx-%lx) for %s\n",
- i, res->start, res->end, dev->slot_name);
- return -EBUSY;
- }
+ ret = pci_bus_alloc_resource(bus, res, size, align, min, 0,
+ pcibios_align_resource, dev);
}
- DBGC((KERN_ERR " got res[%lx:%lx] for resource %d of %s\n", res->start,
- res->end, i, dev->dev.name));
+ if (ret) {
+ printk(KERN_ERR "PCI: Failed to allocate resource %d(%lx-%lx) for %s\n",
+ resno, res->start, res->end, dev->slot_name);
+ } else {
+ DBGC((KERN_ERR " got res[%lx:%lx] for resource %d of %s\n",
+ res->start, res->end, i, dev->dev.name));
+ /* Update PCI config space. */
+ pcibios_update_resource(dev, res->parent, res, resno);
+ }
- return 0;
+ return ret;
}
/* Sort resources by alignment */
--- orig/include/linux/pci.h Sun Mar 2 22:42:29 2003
+++ linux/include/linux/pci.h Sat Mar 1 15:36:42 2003
@@ -641,6 +641,16 @@
int pci_request_region(struct pci_dev *, int, char *);
void pci_release_region(struct pci_dev *, int);
+/* drivers/pci/bus.c */
+
+int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
+ unsigned long size, unsigned long align,
+ unsigned long min, unsigned int type_mask,
+ void (*alignf)(void *, struct resource *,
+ unsigned long, unsigned long),
+ void *alignf_data);
+void pci_enable_bridges(struct pci_bus *bus);
+
/* New-style probing supporting hot-pluggable devices */
int pci_register_driver(struct pci_driver *);
void pci_unregister_driver(struct pci_driver *);
--
Russell King (rmk@arm.linux.org.uk) The developer of ARM Linux
http://www.arm.linux.org.uk/personal/aboutme.html
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [CFT] PCI probing for cardbus (2/5)
2003-03-05 0:36 [CFT] PCI probing for cardbus Russell King
2003-03-05 0:39 ` [CFT] PCI probing for cardbus (1/5) Russell King
@ 2003-03-05 0:39 ` Russell King
2003-03-05 0:40 ` [CFT] PCI probing for cardbus (3/5) Russell King
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Russell King @ 2003-03-05 0:39 UTC (permalink / raw)
To: Linux Kernel List
diff -ur orig/drivers/hotplug/acpiphp_glue.c linux/drivers/hotplug/acpiphp_glue.c
--- orig/drivers/hotplug/acpiphp_glue.c Tue Feb 11 16:10:08 2003
+++ linux/drivers/hotplug/acpiphp_glue.c Mon Feb 24 11:28:46 2003
@@ -879,7 +879,7 @@
static int enable_device (struct acpiphp_slot *slot)
{
u8 bus;
- struct pci_dev dev0, *dev;
+ struct pci_dev *dev;
struct pci_bus *child;
struct list_head *l;
struct acpiphp_func *func;
@@ -902,16 +902,8 @@
if (retval)
goto err_exit;
- memset(&dev0, 0, sizeof (struct pci_dev));
-
- dev0.bus = slot->bridge->pci_bus;
- dev0.devfn = PCI_DEVFN(slot->device, 0);
- dev0.sysdata = dev0.bus->sysdata;
- dev0.dev.parent = dev0.bus->dev;
- dev0.dev.bus = &pci_bus_type;
-
/* returned `dev' is the *first function* only! */
- dev = pci_scan_slot (&dev0);
+ dev = pci_scan_slot(slot->bridge->pci_bus, PCI_DEVFN(slot->device, 0));
if (!dev) {
err("No new device found\n");
diff -ur orig/drivers/hotplug/cpci_hotplug_pci.c linux/drivers/hotplug/cpci_hotplug_pci.c
--- orig/drivers/hotplug/cpci_hotplug_pci.c Tue Feb 11 16:10:08 2003
+++ linux/drivers/hotplug/cpci_hotplug_pci.c Mon Feb 24 11:29:36 2003
@@ -601,19 +601,13 @@
/* Still NULL? Well then scan for it! */
if(slot->dev == NULL) {
- struct pci_dev dev0;
-
dbg("pci_dev still null");
- memset(&dev0, 0, sizeof (struct pci_dev));
- dev0.bus = slot->bus;
- dev0.devfn = slot->devfn;
- dev0.sysdata = slot->bus->self->sysdata;
/*
* This will generate pci_dev structures for all functions, but
* we will only call this case when lookup fails.
*/
- slot->dev = pci_scan_slot(&dev0);
+ slot->dev = pci_scan_slot(slot->bus, slot->devfn);
if(slot->dev == NULL) {
err("Could not find PCI device for slot %02x", slot->number);
return 0;
diff -ur orig/drivers/hotplug/cpqphp_pci.c linux/drivers/hotplug/cpqphp_pci.c
--- orig/drivers/hotplug/cpqphp_pci.c Tue Feb 11 16:10:09 2003
+++ linux/drivers/hotplug/cpqphp_pci.c Mon Feb 24 11:31:07 2003
@@ -250,7 +250,6 @@
int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func)
{
unsigned char bus;
- struct pci_dev dev0;
struct pci_bus *child;
struct pci_dev* temp;
int rc = 0;
@@ -260,20 +259,16 @@
memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
- memset(&dev0, 0, sizeof(struct pci_dev));
-
if (func->pci_dev == NULL)
func->pci_dev = pci_find_slot(func->bus, (func->device << 3) | (func->function & 0x7));
//Still NULL ? Well then scan for it !
if (func->pci_dev == NULL) {
dbg("INFO: pci_dev still null\n");
- dev0.bus = ctrl->pci_dev->bus;
- dev0.devfn = (func->device << 3) + (func->function & 0x7);
- dev0.sysdata = ctrl->pci_dev->sysdata;
//this will generate pci_dev structures for all functions, but we will only call this case when lookup fails
- func->pci_dev = pci_scan_slot(&dev0);
+ func->pci_dev = pci_scan_slot(ctrl->pci_dev->bus,
+ (func->device << 3) + (func->function & 0x7));
if (func->pci_dev == NULL) {
dbg("ERROR: pci_dev still null\n");
return 0;
diff -ur orig/drivers/hotplug/ibmphp_core.c linux/drivers/hotplug/ibmphp_core.c
--- orig/drivers/hotplug/ibmphp_core.c Tue Feb 11 16:10:09 2003
+++ linux/drivers/hotplug/ibmphp_core.c Mon Feb 24 11:32:11 2003
@@ -1035,7 +1035,6 @@
static int ibm_configure_device (struct pci_func *func)
{
unsigned char bus;
- struct pci_dev dev0;
struct pci_bus *child;
struct pci_dev *temp;
int rc = 0;
@@ -1046,7 +1045,6 @@
memset (&wrapped_dev, 0, sizeof (struct pci_dev_wrapped));
memset (&wrapped_bus, 0, sizeof (struct pci_bus_wrapped));
- memset (&dev0, 0, sizeof (struct pci_dev));
if (!(bus_structure_fixup (func->busno)))
flag = 1;
@@ -1054,13 +1052,12 @@
func->dev = pci_find_slot (func->busno, (func->device << 3) | (func->function & 0x7));
if (func->dev == NULL) {
- dev0.bus = ibmphp_find_bus (func->busno);
- if (!dev0.bus)
+ struct pci_bus *bus = ibmphp_find_bus (func->busno);
+ if (!bus)
return 0;
- dev0.devfn = ((func->device << 3) + (func->function & 0x7));
- dev0.sysdata = dev0.bus->sysdata;
- func->dev = pci_scan_slot (&dev0);
+ func->dev = pci_scan_slot(bus,
+ (func->device << 3) + (func->function & 0x7));
if (func->dev == NULL) {
err ("ERROR... : pci_dev still NULL \n");
--- orig/drivers/pci/probe.c Mon Jan 13 22:32:31 2003
+++ linux/drivers/pci/probe.c Mon Feb 24 14:01:48 2003
@@ -374,7 +374,8 @@
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);
+ DBG("Found %02x:%02x [%04x/%04x] %06x %02x\n", dev->bus->number, dev->devfn,
+ dev->vendor, dev->device, class, dev->hdr_type);
/* "Unknown power state" */
dev->current_state = 4;
@@ -427,23 +428,35 @@
* Read the config data for a PCI device, sanity-check it
* and fill in the dev structure...
*/
-struct pci_dev * __devinit pci_scan_device(struct pci_dev *temp)
+static struct pci_dev * __devinit
+pci_scan_device(struct pci_bus *bus, int devfn)
{
struct pci_dev *dev;
u32 l;
+ u8 hdr_type;
+
+ if (pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type))
+ return NULL;
- if (pci_read_config_dword(temp, PCI_VENDOR_ID, &l))
+ if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l))
return NULL;
/* some broken boards return 0 or ~0 if a slot is empty: */
if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000)
return NULL;
- dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ dev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
if (!dev)
return NULL;
- memcpy(dev, temp, sizeof(*dev));
+ memset(dev, 0, sizeof(struct pci_dev));
+ dev->bus = bus;
+ dev->sysdata = bus->sysdata;
+ dev->dev.parent = bus->dev;
+ dev->dev.bus = &pci_bus_type;
+ dev->devfn = devfn;
+ dev->hdr_type = hdr_type & 0x7f;
+ dev->multifunction = !!(hdr_type & 0x80);
dev->vendor = l & 0xffff;
dev->device = (l >> 16) & 0xffff;
@@ -461,42 +474,44 @@
strcpy(dev->dev.bus_id,dev->slot_name);
dev->dev.dma_mask = &dev->dma_mask;
- device_register(&dev->dev);
return dev;
}
-struct pci_dev * __devinit pci_scan_slot(struct pci_dev *temp)
+struct pci_dev * __devinit pci_scan_slot(struct pci_bus *bus, int devfn)
{
- struct pci_bus *bus = temp->bus;
- struct pci_dev *dev;
struct pci_dev *first_dev = NULL;
- int func = 0;
- int is_multi = 0;
- u8 hdr_type;
+ int func;
- for (func = 0; func < 8; func++, temp->devfn++) {
- if (func && !is_multi) /* not a multi-function device */
- continue;
- if (pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type))
- continue;
- temp->hdr_type = hdr_type & 0x7f;
+ for (func = 0; func < 8; func++, devfn++) {
+ struct pci_dev *dev;
- dev = pci_scan_device(temp);
+ dev = pci_scan_device(bus, devfn);
if (!dev)
continue;
- if (!func) {
- is_multi = hdr_type & 0x80;
+
+ if (func == 0) {
first_dev = dev;
+ } else {
+ dev->multifunction = 1;
}
+ /* Fix up broken headers */
+ pci_fixup_device(PCI_FIXUP_HEADER, dev);
+
/*
* Link the device to both the global PCI device chain and
* the per-bus list of devices and add the /proc entry.
+ * Note: this also runs the hotplug notifiers (bad!) --rmk
*/
+ device_register(&dev->dev);
pci_insert_device (dev, bus);
- /* Fix up broken headers */
- pci_fixup_device(PCI_FIXUP_HEADER, dev);
+ /*
+ * If this is a single function device,
+ * don't scan past the first function.
+ */
+ if (!dev->multifunction)
+ break;
}
return first_dev;
}
@@ -507,28 +522,12 @@
struct list_head *ln;
struct pci_dev *dev;
- dev = kmalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev) {
- printk(KERN_ERR "Out of memory in %s\n", __FUNCTION__);
- return 0;
- }
-
DBG("Scanning bus %02x\n", bus->number);
max = bus->secondary;
- /* Create a device template */
- memset(dev, 0, sizeof(*dev));
- dev->bus = bus;
- dev->sysdata = bus->sysdata;
- dev->dev.parent = bus->dev;
- dev->dev.bus = &pci_bus_type;
-
/* Go find them, Rover! */
- for (devfn = 0; devfn < 0x100; devfn += 8) {
- dev->devfn = devfn;
- pci_scan_slot(dev);
- }
- kfree(dev);
+ for (devfn = 0; devfn < 0x100; devfn += 8)
+ pci_scan_slot(bus, devfn);
/*
* After performing arch-dependent fixup of the bus, look behind
@@ -537,9 +536,9 @@
DBG("Fixups for bus %02x\n", bus->number);
pcibios_fixup_bus(bus);
for (pass=0; pass < 2; pass++)
- for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
- dev = pci_dev_b(ln);
- if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
+ dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
max = pci_scan_bridge(bus, dev, max, pass);
}
--- orig/include/linux/pci.h Fri Feb 21 19:48:58 2003
+++ linux/include/linux/pci.h Mon Feb 24 12:51:22 2003
@@ -413,6 +413,7 @@
/* These fields are used by common fixups */
unsigned int transparent:1; /* Transparent PCI bridge */
+ unsigned int multifunction:1;/* Part of multi-function device */
};
#define pci_dev_g(n) list_entry(n, struct pci_dev, global_list)
@@ -548,7 +549,7 @@
{
return pci_alloc_primary_bus_parented(NULL, bus);
}
-struct pci_dev *pci_scan_slot(struct pci_dev *temp);
+struct pci_dev *pci_scan_slot(struct pci_bus *bus, int devfn);
int pci_proc_attach_device(struct pci_dev *dev);
int pci_proc_detach_device(struct pci_dev *dev);
int pci_proc_attach_bus(struct pci_bus *bus);
--
Russell King (rmk@arm.linux.org.uk) The developer of ARM Linux
http://www.arm.linux.org.uk/personal/aboutme.html
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [CFT] PCI probing for cardbus (3/5)
2003-03-05 0:36 [CFT] PCI probing for cardbus Russell King
2003-03-05 0:39 ` [CFT] PCI probing for cardbus (1/5) Russell King
2003-03-05 0:39 ` [CFT] PCI probing for cardbus (2/5) Russell King
@ 2003-03-05 0:40 ` Russell King
2003-03-05 0:40 ` [CFT] PCI probing for cardbus (4/5) Russell King
2003-03-05 0:40 ` [CFT] PCI probing for cardbus (5/5) Russell King
4 siblings, 0 replies; 6+ messages in thread
From: Russell King @ 2003-03-05 0:40 UTC (permalink / raw)
To: Linux Kernel List
diff -u orig/drivers/pci/bus.c linux/drivers/pci/bus.c
--- orig/drivers/pci/bus.c Mon Mar 3 21:24:55 2003
+++ orig/drivers/pci/bus.c Mon Mar 3 21:26:41 2003
@@ -12,6 +12,10 @@
#include <linux/pci.h>
#include <linux/errno.h>
#include <linux/ioport.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+
+#include "pci.h"
/**
* pci_bus_alloc_resource - allocate a resource from a parent bus
@@ -64,6 +68,47 @@
return ret;
}
+/**
+ * pci_bus_add_devices - insert newly discovered PCI devices
+ * @bus: bus to check for new devices
+ *
+ * Add newly discovered PCI devices (which are on the bus->devices
+ * list) to the global PCI device list, add the sysfs and procfs
+ * entries. Where a bridge is found, add the discovered bus to
+ * the parents list of child buses, and recurse.
+ *
+ * Call hotplug for each new devices.
+ */
+void __devinit pci_bus_add_devices(struct pci_bus *bus)
+{
+ struct pci_dev *dev;
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ /*
+ * Skip already-present devices (which are on the
+ * global device list.)
+ */
+ if (!list_empty(&dev->global_list))
+ continue;
+
+ device_register(&dev->dev);
+ list_add_tail(&dev->global_list, &pci_devices);
+#ifdef CONFIG_PROC_FS
+ pci_proc_attach_device(dev);
+#endif
+ pci_create_sysfs_dev_files(dev);
+
+ /*
+ * If there is an unattached subordinate bus, attach
+ * it and then scan for unattached PCI devices.
+ */
+ if (dev->subordinate && list_empty(&dev->subordinate->node)) {
+ list_add_tail(&dev->subordinate->node, &dev->bus->children);
+ pci_bus_add_devices(dev->subordinate);
+ }
+ }
+}
+
void pci_enable_bridges(struct pci_bus *bus)
{
struct pci_dev *dev;
@@ -78,4 +123,5 @@
}
EXPORT_SYMBOL(pci_bus_alloc_resource);
+EXPORT_SYMBOL(pci_bus_add_devices);
EXPORT_SYMBOL(pci_enable_bridges);
diff -u orig/drivers/pci/probe.c linux/drivers/pci/probe.c
--- orig/drivers/pci/probe.c Mon Mar 3 21:24:47 2003
+++ linux/drivers/pci/probe.c Mon Mar 3 21:25:47 2003
@@ -221,6 +221,7 @@
b = kmalloc(sizeof(*b), GFP_KERNEL);
if (b) {
memset(b, 0, sizeof(*b));
+ INIT_LIST_HEAD(&b->node);
INIT_LIST_HEAD(&b->children);
INIT_LIST_HEAD(&b->devices);
}
@@ -477,10 +478,18 @@
return dev;
}
-struct pci_dev * __devinit pci_scan_slot(struct pci_bus *bus, int devfn)
+/**
+ * pci_scan_slot - scan a PCI slot on a bus for devices.
+ * @bus: PCI bus to scan
+ * @devfn: slot number to scan (must have zero function.)
+ *
+ * Scan a PCI slot on the specified PCI bus for devices, adding
+ * discovered devices to the @bus->devices list. New devices
+ * will have an empty dev->global_list head.
+ */
+int __devinit pci_scan_slot(struct pci_bus *bus, int devfn)
{
- struct pci_dev *first_dev = NULL;
- int func;
+ int func, nr = 0;
for (func = 0; func < 8; func++, devfn++) {
struct pci_dev *dev;
@@ -489,22 +498,19 @@
if (!dev)
continue;
- if (func == 0) {
- first_dev = dev;
- } else {
+ if (func != 0)
dev->multifunction = 1;
- }
/* Fix up broken headers */
pci_fixup_device(PCI_FIXUP_HEADER, dev);
/*
- * Link the device to both the global PCI device chain and
- * the per-bus list of devices and add the /proc entry.
- * Note: this also runs the hotplug notifiers (bad!) --rmk
+ * Add the device to our list of discovered devices
+ * and the bus list for fixup functions, etc.
*/
- device_register(&dev->dev);
- pci_insert_device (dev, bus);
+ INIT_LIST_HEAD(&dev->global_list);
+ list_add_tail(&dev->bus_list, &bus->devices);
+ nr++;
/*
* If this is a single function device,
@@ -513,17 +519,15 @@
if (!dev->multifunction)
break;
}
- return first_dev;
+ return nr;
}
-unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
+static unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
{
- unsigned int devfn, max, pass;
- struct list_head *ln;
+ unsigned int devfn, pass, max = bus->secondary;
struct pci_dev *dev;
DBG("Scanning bus %02x\n", bus->number);
- max = bus->secondary;
/* Go find them, Rover! */
for (devfn = 0; devfn < 0x100; devfn += 8)
@@ -550,6 +554,20 @@
* Return how far we've got finding sub-buses.
*/
DBG("Bus scan for %02x returning with max=%02x\n", bus->number, max);
+ return max;
+}
+
+unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
+{
+ unsigned int max;
+
+ max = pci_scan_child_bus(bus);
+
+ /*
+ * Make the discovered devices available.
+ */
+ pci_bus_add_devices(bus);
+
return max;
}
--- orig/include/linux/pci.h Tue Feb 25 23:34:29 2003
+++ linux/include/linux/pci.h Tue Feb 25 23:37:27 2003
@@ -549,7 +549,8 @@
{
return pci_alloc_primary_bus_parented(NULL, bus);
}
-struct pci_dev *pci_scan_slot(struct pci_bus *bus, int devfn);
+int pci_scan_slot(struct pci_bus *bus, int devfn);
+void pci_bus_add_devices(struct pci_bus *bus);
int pci_proc_attach_device(struct pci_dev *dev);
int pci_proc_detach_device(struct pci_dev *dev);
int pci_proc_attach_bus(struct pci_bus *bus);
--
Russell King (rmk@arm.linux.org.uk) The developer of ARM Linux
http://www.arm.linux.org.uk/personal/aboutme.html
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [CFT] PCI probing for cardbus (4/5)
2003-03-05 0:36 [CFT] PCI probing for cardbus Russell King
` (2 preceding siblings ...)
2003-03-05 0:40 ` [CFT] PCI probing for cardbus (3/5) Russell King
@ 2003-03-05 0:40 ` Russell King
2003-03-05 0:40 ` [CFT] PCI probing for cardbus (5/5) Russell King
4 siblings, 0 replies; 6+ messages in thread
From: Russell King @ 2003-03-05 0:40 UTC (permalink / raw)
To: Linux Kernel List
diff -u orig/drivers/pci/setup-bus.c linux/drivers/pci/setup-bus.c
--- orig/drivers/pci/setup-bus.c Tue Feb 25 10:57:49 2003
+++ linux/drivers/pci/setup-bus.c Tue Feb 25 11:17:33 2003
@@ -350,6 +350,7 @@
{
struct pci_bus *b;
int found_vga = pbus_assign_resources_sorted(bus);
+ struct pci_dev *dev;
if (found_vga) {
/* Propagate presence of the VGA to upstream bridges */
@@ -357,9 +358,12 @@
b->resource[0]->flags |= IORESOURCE_BUS_HAS_VGA;
}
}
- list_for_each_entry(b, &bus->children, node) {
- pci_bus_assign_resources(b);
- pci_setup_bridge(b);
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ b = dev->subordinate;
+ if (b) {
+ pci_bus_assign_resources(b);
+ pci_setup_bridge(b);
+ }
}
}
EXPORT_SYMBOL(pci_bus_assign_resources);
--
Russell King (rmk@arm.linux.org.uk) The developer of ARM Linux
http://www.arm.linux.org.uk/personal/aboutme.html
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [CFT] PCI probing for cardbus (5/5)
2003-03-05 0:36 [CFT] PCI probing for cardbus Russell King
` (3 preceding siblings ...)
2003-03-05 0:40 ` [CFT] PCI probing for cardbus (4/5) Russell King
@ 2003-03-05 0:40 ` Russell King
4 siblings, 0 replies; 6+ messages in thread
From: Russell King @ 2003-03-05 0:40 UTC (permalink / raw)
To: Linux Kernel List
diff -u orig/drivers/pci/probe.c linux/drivers/pci/probe.c
--- orig/drivers/pci/probe.c Tue Feb 25 23:46:00 2003
+++ linux/drivers/pci/probe.c Tue Feb 25 23:47:51 2003
@@ -228,41 +228,57 @@
return b;
}
-struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
+static struct pci_bus * __devinit
+pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr)
{
struct pci_bus *child;
- int i;
/*
* Allocate a new bus, and inherit stuff from the parent..
*/
child = pci_alloc_bus();
- list_add_tail(&child->node, &parent->children);
- child->self = dev;
- dev->subordinate = child;
- child->parent = parent;
- child->ops = parent->ops;
- child->sysdata = parent->sysdata;
- child->dev = &dev->dev;
+ if (child) {
+ int i;
- /*
- * Set up the primary, secondary and subordinate
- * bus numbers.
- */
- child->number = child->secondary = busnr;
- child->primary = parent->secondary;
- child->subordinate = 0xff;
-
- /* Set up default resource pointers and names.. */
- for (i = 0; i < 4; i++) {
- child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
- child->resource[i]->name = child->name;
+ child->self = bridge;
+ child->parent = parent;
+ child->ops = parent->ops;
+ child->sysdata = parent->sysdata;
+ child->dev = &bridge->dev;
+
+ /*
+ * Set up the primary, secondary and subordinate
+ * bus numbers.
+ */
+ child->number = child->secondary = busnr;
+ child->primary = parent->secondary;
+ child->subordinate = 0xff;
+
+ /* Set up default resource pointers and names.. */
+ for (i = 0; i < 4; i++) {
+ child->resource[i] = &bridge->resource[PCI_BRIDGE_RESOURCES+i];
+ child->resource[i]->name = child->name;
+ }
+
+ bridge->subordinate = child;
}
return child;
}
+struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
+{
+ struct pci_bus *child;
+
+ child = pci_alloc_child_bus(parent, dev, busnr);
+ if (child)
+ list_add_tail(&child->node, &parent->children);
+ return child;
+}
+
+static unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus);
+
/*
* If it's a bridge, configure it and scan the bus behind it.
* For CardBus bridges, we don't scan behind as the devices will
@@ -289,12 +305,12 @@
*/
if (pass)
return max;
- child = pci_add_new_bus(bus, dev, 0);
+ child = pci_alloc_child_bus(bus, dev, 0);
child->primary = buses & 0xFF;
child->secondary = (buses >> 8) & 0xFF;
child->subordinate = (buses >> 16) & 0xFF;
child->number = child->secondary;
- cmax = pci_do_scan_bus(child);
+ cmax = pci_scan_child_bus(child);
if (cmax > max) max = cmax;
} else {
/*
@@ -307,18 +323,27 @@
/* Clear errors */
pci_write_config_word(dev, PCI_STATUS, 0xffff);
- child = pci_add_new_bus(bus, dev, ++max);
+ child = pci_alloc_child_bus(bus, dev, ++max);
buses = (buses & 0xff000000)
| ((unsigned int)(child->primary) << 0)
| ((unsigned int)(child->secondary) << 8)
| ((unsigned int)(child->subordinate) << 16);
+
+ /*
+ * yenta.c forces a secondary latency timer of 176.
+ * Copy that behaviour here.
+ */
+ if (is_cardbus)
+ buses = (buses & 0x00ffffff) | (176 << 24);
+
/*
* We need to blast all three values with a single write.
*/
pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
+
if (!is_cardbus) {
/* Now we can scan all subordinate buses... */
- max = pci_do_scan_bus(child);
+ max = pci_scan_child_bus(child);
} else {
/*
* For CardBus bridges, we leave 4 bus numbers
--
Russell King (rmk@arm.linux.org.uk) The developer of ARM Linux
http://www.arm.linux.org.uk/personal/aboutme.html
^ permalink raw reply [flat|nested] 6+ messages in thread