summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorPatrick Mochel <mochel@segfault.osdl.org>2002-04-16 01:06:36 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2002-04-16 01:06:36 -0700
commit9036d433bd2cacb1e0e34219649cd499b733a84d (patch)
treee85c2b58db5bff522f21ac71543730c61e6bafca /drivers
parent8da5f1d4072c4f0d88fbb7a25b2ba1065150ff1d (diff)
Split drivers/pci/pci.c into smaller, bite-size chunks
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pci/Makefile8
-rw-r--r--drivers/pci/access.c46
-rw-r--r--drivers/pci/hotplug.c132
-rw-r--r--drivers/pci/pci-driver.c136
-rw-r--r--drivers/pci/pci.c1520
-rw-r--r--drivers/pci/pool.c335
-rw-r--r--drivers/pci/power.c164
-rw-r--r--drivers/pci/probe.c603
-rw-r--r--drivers/pci/proc.c12
-rw-r--r--drivers/pci/search.c110
10 files changed, 1541 insertions, 1525 deletions
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index a83c36f0d7d2..b713bcb4a1c0 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -11,9 +11,11 @@
O_TARGET := driver.o
-export-objs := pci.o
+obj-y += access.o probe.o pci.o pool.o quirks.o \
+ compat.o names.o pci-driver.o search.o
+obj-$(CONFIG_PM) += power.o
+obj-$(CONFIG_HOTPLUG) += hotplug.o
-obj-$(CONFIG_PCI) += pci.o quirks.o compat.o names.o pci-driver.o
obj-$(CONFIG_PROC_FS) += proc.o
ifndef CONFIG_SPARC64
@@ -35,6 +37,8 @@ ifndef CONFIG_X86
obj-y += syscall.o
endif
+export-objs := $(obj-y)
+
include $(TOPDIR)/Rules.make
names.o: names.c devlist.h classlist.h
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
new file mode 100644
index 000000000000..5546095e5a1f
--- /dev/null
+++ b/drivers/pci/access.c
@@ -0,0 +1,46 @@
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+
+/*
+ * This interrupt-safe spinlock protects all accesses to PCI
+ * configuration space.
+ */
+
+static spinlock_t pci_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Wrappers for all PCI configuration access functions. They just check
+ * alignment, do locking and call the low-level functions pointed to
+ * by pci_dev->ops.
+ */
+
+#define PCI_byte_BAD 0
+#define PCI_word_BAD (pos & 1)
+#define PCI_dword_BAD (pos & 3)
+
+#define PCI_OP(rw,size,type) \
+int pci_##rw##_config_##size (struct pci_dev *dev, int pos, type value) \
+{ \
+ int res; \
+ unsigned long flags; \
+ if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \
+ spin_lock_irqsave(&pci_lock, flags); \
+ res = dev->bus->ops->rw##_##size(dev, pos, value); \
+ spin_unlock_irqrestore(&pci_lock, flags); \
+ return res; \
+}
+
+PCI_OP(read, byte, u8 *)
+PCI_OP(read, word, u16 *)
+PCI_OP(read, dword, u32 *)
+PCI_OP(write, byte, u8)
+PCI_OP(write, word, u16)
+PCI_OP(write, dword, u32)
+
+EXPORT_SYMBOL(pci_read_config_byte);
+EXPORT_SYMBOL(pci_read_config_word);
+EXPORT_SYMBOL(pci_read_config_dword);
+EXPORT_SYMBOL(pci_write_config_byte);
+EXPORT_SYMBOL(pci_write_config_word);
+EXPORT_SYMBOL(pci_write_config_dword);
diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c
new file mode 100644
index 000000000000..90eb3d8d426e
--- /dev/null
+++ b/drivers/pci/hotplug.c
@@ -0,0 +1,132 @@
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/kmod.h> /* for hotplug_path */
+
+extern struct list_head pci_drivers;
+extern int pci_announce_device(struct pci_driver *drv, struct pci_dev *dev);
+
+#ifndef FALSE
+#define FALSE (0)
+#define TRUE (!FALSE)
+#endif
+
+static void
+run_sbin_hotplug(struct pci_dev *pdev, int insert)
+{
+ int i;
+ char *argv[3], *envp[8];
+ char id[20], sub_id[24], bus_id[24], class_id[20];
+
+ if (!hotplug_path[0])
+ return;
+
+ sprintf(class_id, "PCI_CLASS=%04X", pdev->class);
+ sprintf(id, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device);
+ sprintf(sub_id, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, pdev->subsystem_device);
+ sprintf(bus_id, "PCI_SLOT_NAME=%s", pdev->slot_name);
+
+ i = 0;
+ argv[i++] = hotplug_path;
+ argv[i++] = "pci";
+ argv[i] = 0;
+
+ i = 0;
+ /* minimal command environment */
+ envp[i++] = "HOME=/";
+ envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+
+ /* other stuff we want to pass to /sbin/hotplug */
+ envp[i++] = class_id;
+ envp[i++] = id;
+ envp[i++] = sub_id;
+ envp[i++] = bus_id;
+ if (insert)
+ envp[i++] = "ACTION=add";
+ else
+ envp[i++] = "ACTION=remove";
+ envp[i] = 0;
+
+ call_usermodehelper (argv [0], argv, envp);
+}
+
+/**
+ * pci_announce_device_to_drivers - tell the drivers a new device has appeared
+ * @dev: the device that has shown up
+ *
+ * Notifys the drivers that a new device has appeared, and also notifys
+ * userspace through /sbin/hotplug.
+ */
+void
+pci_announce_device_to_drivers(struct pci_dev *dev)
+{
+ struct list_head *ln;
+
+ for(ln=pci_drivers.next; ln != &pci_drivers; ln=ln->next) {
+ struct pci_driver *drv = list_entry(ln, struct pci_driver, node);
+ if (drv->remove && pci_announce_device(drv, dev))
+ break;
+ }
+
+ /* notify userspace of new hotplug device */
+ run_sbin_hotplug(dev, TRUE);
+}
+
+/**
+ * pci_insert_device - insert a hotplug device
+ * @dev: the device to insert
+ * @bus: where to insert it
+ *
+ * Add a new device to the device lists and notify userspace (/sbin/hotplug).
+ */
+void
+pci_insert_device(struct pci_dev *dev, struct pci_bus *bus)
+{
+ list_add_tail(&dev->bus_list, &bus->devices);
+ list_add_tail(&dev->global_list, &pci_devices);
+#ifdef CONFIG_PROC_FS
+ pci_proc_attach_device(dev);
+#endif
+ pci_announce_device_to_drivers(dev);
+}
+
+static void
+pci_free_resources(struct pci_dev *dev)
+{
+ int i;
+
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ struct resource *res = dev->resource + i;
+ if (res->parent)
+ release_resource(res);
+ }
+}
+
+/**
+ * pci_remove_device - remove a hotplug device
+ * @dev: the device to remove
+ *
+ * Delete the device structure from the device lists and
+ * notify userspace (/sbin/hotplug).
+ */
+void
+pci_remove_device(struct pci_dev *dev)
+{
+ if (dev->driver) {
+ if (dev->driver->remove)
+ dev->driver->remove(dev);
+ dev->driver = NULL;
+ }
+ list_del(&dev->bus_list);
+ list_del(&dev->global_list);
+ pci_free_resources(dev);
+#ifdef CONFIG_PROC_FS
+ pci_proc_detach_device(dev);
+#endif
+
+ /* notify userspace of hotplug device removal */
+ run_sbin_hotplug(dev, FALSE);
+}
+
+EXPORT_SYMBOL(pci_insert_device);
+EXPORT_SYMBOL(pci_remove_device);
+EXPORT_SYMBOL(pci_announce_device_to_drivers);
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 1b03c56056a4..702542470631 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -1,9 +1,138 @@
/*
- * drivers/pci/pci-driver.c - default PCI driver.
+ * drivers/pci/pci-driver.c
*
*/
#include <linux/pci.h>
+#include <linux/module.h>
+
+/*
+ * Registration of PCI drivers and handling of hot-pluggable devices.
+ */
+
+LIST_HEAD(pci_drivers);
+
+/**
+ * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure
+ * @ids: array of PCI device id structures to search in
+ * @dev: the PCI device structure to match against
+ *
+ * Used by a driver to check whether a PCI device present in the
+ * system is in its list of supported devices.Returns the matching
+ * pci_device_id structure or %NULL if there is no match.
+ */
+const struct pci_device_id *
+pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev)
+{
+ while (ids->vendor || ids->subvendor || ids->class_mask) {
+ if ((ids->vendor == PCI_ANY_ID || ids->vendor == dev->vendor) &&
+ (ids->device == PCI_ANY_ID || ids->device == dev->device) &&
+ (ids->subvendor == PCI_ANY_ID || ids->subvendor == dev->subsystem_vendor) &&
+ (ids->subdevice == PCI_ANY_ID || ids->subdevice == dev->subsystem_device) &&
+ !((ids->class ^ dev->class) & ids->class_mask))
+ return ids;
+ ids++;
+ }
+ return NULL;
+}
+
+int
+pci_announce_device(struct pci_driver *drv, struct pci_dev *dev)
+{
+ const struct pci_device_id *id;
+ int ret = 0;
+
+ if (drv->id_table) {
+ id = pci_match_device(drv->id_table, dev);
+ if (!id) {
+ ret = 0;
+ goto out;
+ }
+ } else
+ id = NULL;
+
+ dev_probe_lock();
+ if (drv->probe(dev, id) >= 0) {
+ dev->driver = drv;
+ ret = 1;
+ }
+ dev_probe_unlock();
+out:
+ return ret;
+}
+
+/**
+ * pci_register_driver - register a new pci driver
+ * @drv: the driver structure to register
+ *
+ * Adds the driver structure to the list of registered drivers
+ * Returns the number of pci devices which were claimed by the driver
+ * during registration. The driver remains registered even if the
+ * return value is zero.
+ */
+int
+pci_register_driver(struct pci_driver *drv)
+{
+ struct pci_dev *dev;
+ int count = 0;
+
+ list_add_tail(&drv->node, &pci_drivers);
+ pci_for_each_dev(dev) {
+ if (!pci_dev_driver(dev))
+ count += pci_announce_device(drv, dev);
+ }
+ return count;
+}
+
+/**
+ * pci_unregister_driver - unregister a pci driver
+ * @drv: the driver structure to unregister
+ *
+ * Deletes the driver structure from the list of registered PCI drivers,
+ * gives it a chance to clean up by calling its remove() function for
+ * each device it was responsible for, and marks those devices as
+ * driverless.
+ */
+
+void
+pci_unregister_driver(struct pci_driver *drv)
+{
+ struct pci_dev *dev;
+
+ list_del(&drv->node);
+ pci_for_each_dev(dev) {
+ if (dev->driver == drv) {
+ if (drv->remove)
+ drv->remove(dev);
+ dev->driver = NULL;
+ }
+ }
+}
+
+static struct pci_driver pci_compat_driver = {
+ name: "compat"
+};
+
+/**
+ * pci_dev_driver - get the pci_driver of a device
+ * @dev: the device to query
+ *
+ * Returns the appropriate pci_driver structure or %NULL if there is no
+ * registered driver for the device.
+ */
+struct pci_driver *
+pci_dev_driver(const struct pci_dev *dev)
+{
+ if (dev->driver)
+ return dev->driver;
+ else {
+ int i;
+ for(i=0; i<=PCI_ROM_RESOURCE; i++)
+ if (dev->resource[i].flags & IORESOURCE_BUSY)
+ return &pci_compat_driver;
+ }
+ return NULL;
+}
static int pci_device_suspend(struct device * dev, u32 state, u32 level)
{
@@ -34,3 +163,8 @@ struct device_driver pci_device_driver = {
suspend: pci_device_suspend,
resume: pci_device_resume,
};
+
+EXPORT_SYMBOL(pci_match_device);
+EXPORT_SYMBOL(pci_register_driver);
+EXPORT_SYMBOL(pci_unregister_driver);
+EXPORT_SYMBOL(pci_dev_driver);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 3ccb2eb63a2c..27e532c1ac1e 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -9,23 +9,9 @@
* Copyright 1997 -- 2000 Martin Mares <mj@ucw.cz>
*/
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
#include <linux/pci.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
+#include <linux/module.h>
#include <linux/spinlock.h>
-#include <linux/pm.h>
-#include <linux/kmod.h> /* for hotplug_path */
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/cache.h>
-
-#include <asm/page.h>
#include <asm/dma.h> /* isa_dma_bridge_buggy */
#undef DEBUG
@@ -36,114 +22,6 @@
#define DBG(x...)
#endif
-LIST_HEAD(pci_root_buses);
-LIST_HEAD(pci_devices);
-
-extern struct device_driver pci_device_driver;
-
-/**
- * pci_find_slot - locate PCI device from a given PCI slot
- * @bus: number of PCI bus on which desired PCI device resides
- * @devfn: encodes number of PCI slot in which the desired PCI
- * device resides and the logical device number within that slot
- * in case of multi-function devices.
- *
- * Given a PCI bus and slot/function number, the desired PCI device
- * is located in system global list of PCI devices. If the device
- * is found, a pointer to its data structure is returned. If no
- * device is found, %NULL is returned.
- */
-struct pci_dev *
-pci_find_slot(unsigned int bus, unsigned int devfn)
-{
- struct pci_dev *dev;
-
- pci_for_each_dev(dev) {
- if (dev->bus->number == bus && dev->devfn == devfn)
- return dev;
- }
- return NULL;
-}
-
-/**
- * pci_find_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
- * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
- * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
- * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids
- * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
- * @from: Previous PCI device found in search, or %NULL for new search.
- *
- * Iterates through the list of known PCI devices. If a PCI device is
- * found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
- * device structure is returned. Otherwise, %NULL is returned.
- * A new search is initiated by passing %NULL to the @from argument.
- * Otherwise if @from is not %NULL, searches continue from next device on the global list.
- */
-struct pci_dev *
-pci_find_subsys(unsigned int vendor, unsigned int device,
- unsigned int ss_vendor, unsigned int ss_device,
- const struct pci_dev *from)
-{
- struct list_head *n = from ? from->global_list.next : pci_devices.next;
-
- while (n != &pci_devices) {
- struct pci_dev *dev = pci_dev_g(n);
- if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
- (device == PCI_ANY_ID || dev->device == device) &&
- (ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) &&
- (ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device))
- return dev;
- n = n->next;
- }
- return NULL;
-}
-
-
-/**
- * pci_find_device - begin or continue searching for a PCI device by vendor/device id
- * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
- * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
- * @from: Previous PCI device found in search, or %NULL for new search.
- *
- * Iterates through the list of known PCI devices. If a PCI device is
- * found with a matching @vendor and @device, a pointer to its device structure is
- * returned. Otherwise, %NULL is returned.
- * A new search is initiated by passing %NULL to the @from argument.
- * Otherwise if @from is not %NULL, searches continue from next device on the global list.
- */
-struct pci_dev *
-pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from)
-{
- return pci_find_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
-}
-
-
-/**
- * pci_find_class - begin or continue searching for a PCI device by class
- * @class: search for a PCI device with this class designation
- * @from: Previous PCI device found in search, or %NULL for new search.
- *
- * Iterates through the list of known PCI devices. If a PCI device is
- * found with a matching @class, a pointer to its device structure is
- * returned. Otherwise, %NULL is returned.
- * A new search is initiated by passing %NULL to the @from argument.
- * Otherwise if @from is not %NULL, searches continue from next device
- * on the global list.
- */
-struct pci_dev *
-pci_find_class(unsigned int class, const struct pci_dev *from)
-{
- struct list_head *n = from ? from->global_list.next : pci_devices.next;
-
- while (n != &pci_devices) {
- struct pci_dev *dev = pci_dev_g(n);
- if (dev->class == class)
- return dev;
- n = n->next;
- }
- return NULL;
-}
-
/**
* pci_find_capability - query for devices' capabilities
* @dev: PCI device to query
@@ -536,298 +414,6 @@ err_out:
return -EBUSY;
}
-
-/*
- * Registration of PCI drivers and handling of hot-pluggable devices.
- */
-
-static LIST_HEAD(pci_drivers);
-
-/**
- * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure
- * @ids: array of PCI device id structures to search in
- * @dev: the PCI device structure to match against
- *
- * Used by a driver to check whether a PCI device present in the
- * system is in its list of supported devices.Returns the matching
- * pci_device_id structure or %NULL if there is no match.
- */
-const struct pci_device_id *
-pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev)
-{
- while (ids->vendor || ids->subvendor || ids->class_mask) {
- if ((ids->vendor == PCI_ANY_ID || ids->vendor == dev->vendor) &&
- (ids->device == PCI_ANY_ID || ids->device == dev->device) &&
- (ids->subvendor == PCI_ANY_ID || ids->subvendor == dev->subsystem_vendor) &&
- (ids->subdevice == PCI_ANY_ID || ids->subdevice == dev->subsystem_device) &&
- !((ids->class ^ dev->class) & ids->class_mask))
- return ids;
- ids++;
- }
- return NULL;
-}
-
-static int
-pci_announce_device(struct pci_driver *drv, struct pci_dev *dev)
-{
- const struct pci_device_id *id;
- int ret = 0;
-
- if (drv->id_table) {
- id = pci_match_device(drv->id_table, dev);
- if (!id) {
- ret = 0;
- goto out;
- }
- } else
- id = NULL;
-
- dev_probe_lock();
- if (drv->probe(dev, id) >= 0) {
- dev->driver = drv;
- ret = 1;
- }
- dev_probe_unlock();
-out:
- return ret;
-}
-
-/**
- * pci_register_driver - register a new pci driver
- * @drv: the driver structure to register
- *
- * Adds the driver structure to the list of registered drivers
- * Returns the number of pci devices which were claimed by the driver
- * during registration. The driver remains registered even if the
- * return value is zero.
- */
-int
-pci_register_driver(struct pci_driver *drv)
-{
- struct pci_dev *dev;
- int count = 0;
-
- list_add_tail(&drv->node, &pci_drivers);
- pci_for_each_dev(dev) {
- if (!pci_dev_driver(dev))
- count += pci_announce_device(drv, dev);
- }
- return count;
-}
-
-/**
- * pci_unregister_driver - unregister a pci driver
- * @drv: the driver structure to unregister
- *
- * Deletes the driver structure from the list of registered PCI drivers,
- * gives it a chance to clean up by calling its remove() function for
- * each device it was responsible for, and marks those devices as
- * driverless.
- */
-
-void
-pci_unregister_driver(struct pci_driver *drv)
-{
- struct pci_dev *dev;
-
- list_del(&drv->node);
- pci_for_each_dev(dev) {
- if (dev->driver == drv) {
- if (drv->remove)
- drv->remove(dev);
- dev->driver = NULL;
- }
- }
-}
-
-#ifdef CONFIG_HOTPLUG
-
-#ifndef FALSE
-#define FALSE (0)
-#define TRUE (!FALSE)
-#endif
-
-static void
-run_sbin_hotplug(struct pci_dev *pdev, int insert)
-{
- int i;
- char *argv[3], *envp[8];
- char id[20], sub_id[24], bus_id[24], class_id[20];
-
- if (!hotplug_path[0])
- return;
-
- sprintf(class_id, "PCI_CLASS=%04X", pdev->class);
- sprintf(id, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device);
- sprintf(sub_id, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, pdev->subsystem_device);
- sprintf(bus_id, "PCI_SLOT_NAME=%s", pdev->slot_name);
-
- i = 0;
- argv[i++] = hotplug_path;
- argv[i++] = "pci";
- argv[i] = 0;
-
- i = 0;
- /* minimal command environment */
- envp[i++] = "HOME=/";
- envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-
- /* other stuff we want to pass to /sbin/hotplug */
- envp[i++] = class_id;
- envp[i++] = id;
- envp[i++] = sub_id;
- envp[i++] = bus_id;
- if (insert)
- envp[i++] = "ACTION=add";
- else
- envp[i++] = "ACTION=remove";
- envp[i] = 0;
-
- call_usermodehelper (argv [0], argv, envp);
-}
-
-/**
- * pci_announce_device_to_drivers - tell the drivers a new device has appeared
- * @dev: the device that has shown up
- *
- * Notifys the drivers that a new device has appeared, and also notifys
- * userspace through /sbin/hotplug.
- */
-void
-pci_announce_device_to_drivers(struct pci_dev *dev)
-{
- struct list_head *ln;
-
- for(ln=pci_drivers.next; ln != &pci_drivers; ln=ln->next) {
- struct pci_driver *drv = list_entry(ln, struct pci_driver, node);
- if (drv->remove && pci_announce_device(drv, dev))
- break;
- }
-
- /* notify userspace of new hotplug device */
- run_sbin_hotplug(dev, TRUE);
-}
-
-/**
- * pci_insert_device - insert a hotplug device
- * @dev: the device to insert
- * @bus: where to insert it
- *
- * Add a new device to the device lists and notify userspace (/sbin/hotplug).
- */
-void
-pci_insert_device(struct pci_dev *dev, struct pci_bus *bus)
-{
- list_add_tail(&dev->bus_list, &bus->devices);
- list_add_tail(&dev->global_list, &pci_devices);
-#ifdef CONFIG_PROC_FS
- pci_proc_attach_device(dev);
-#endif
- pci_announce_device_to_drivers(dev);
-}
-
-static void
-pci_free_resources(struct pci_dev *dev)
-{
- int i;
-
- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
- struct resource *res = dev->resource + i;
- if (res->parent)
- release_resource(res);
- }
-}
-
-/**
- * pci_remove_device - remove a hotplug device
- * @dev: the device to remove
- *
- * Delete the device structure from the device lists and
- * notify userspace (/sbin/hotplug).
- */
-void
-pci_remove_device(struct pci_dev *dev)
-{
- if (dev->driver) {
- if (dev->driver->remove)
- dev->driver->remove(dev);
- dev->driver = NULL;
- }
- list_del(&dev->bus_list);
- list_del(&dev->global_list);
- pci_free_resources(dev);
-#ifdef CONFIG_PROC_FS
- pci_proc_detach_device(dev);
-#endif
-
- /* notify userspace of hotplug device removal */
- run_sbin_hotplug(dev, FALSE);
-}
-
-#endif
-
-static struct pci_driver pci_compat_driver = {
- name: "compat"
-};
-
-/**
- * pci_dev_driver - get the pci_driver of a device
- * @dev: the device to query
- *
- * Returns the appropriate pci_driver structure or %NULL if there is no
- * registered driver for the device.
- */
-struct pci_driver *
-pci_dev_driver(const struct pci_dev *dev)
-{
- if (dev->driver)
- return dev->driver;
- else {
- int i;
- for(i=0; i<=PCI_ROM_RESOURCE; i++)
- if (dev->resource[i].flags & IORESOURCE_BUSY)
- return &pci_compat_driver;
- }
- return NULL;
-}
-
-
-/*
- * This interrupt-safe spinlock protects all accesses to PCI
- * configuration space.
- */
-
-static spinlock_t pci_lock = SPIN_LOCK_UNLOCKED;
-
-/*
- * Wrappers for all PCI configuration access functions. They just check
- * alignment, do locking and call the low-level functions pointed to
- * by pci_dev->ops.
- */
-
-#define PCI_byte_BAD 0
-#define PCI_word_BAD (pos & 1)
-#define PCI_dword_BAD (pos & 3)
-
-#define PCI_OP(rw,size,type) \
-int pci_##rw##_config_##size (struct pci_dev *dev, int pos, type value) \
-{ \
- int res; \
- unsigned long flags; \
- if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \
- spin_lock_irqsave(&pci_lock, flags); \
- res = dev->bus->ops->rw##_##size(dev, pos, value); \
- spin_unlock_irqrestore(&pci_lock, flags); \
- return res; \
-}
-
-PCI_OP(read, byte, u8 *)
-PCI_OP(read, word, u16 *)
-PCI_OP(read, dword, u32 *)
-PCI_OP(write, byte, u8)
-PCI_OP(write, word, u16)
-PCI_OP(write, dword, u32)
-
/**
* pci_set_master - enables bus-mastering for device dev
* @dev: the PCI device to enable
@@ -966,1066 +552,6 @@ pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask)
return 0;
}
-
-/*
- * Translate the low bits of the PCI base
- * to the resource type
- */
-static inline unsigned int pci_calc_resource_flags(unsigned int flags)
-{
- if (flags & PCI_BASE_ADDRESS_SPACE_IO)
- return IORESOURCE_IO;
-
- if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH)
- return IORESOURCE_MEM | IORESOURCE_PREFETCH;
-
- return IORESOURCE_MEM;
-}
-
-/*
- * Find the extent of a PCI decode..
- */
-static u32 pci_size(u32 base, unsigned long mask)
-{
- u32 size = mask & base; /* Find the significant bits */
- size = size & ~(size-1); /* Get the lowest of them to find the decode size */
- return size-1; /* extent = size - 1 */
-}
-
-static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
-{
- unsigned int pos, reg, next;
- u32 l, sz;
- struct resource *res;
-
- for(pos=0; pos<howmany; pos = next) {
- next = pos+1;
- res = &dev->resource[pos];
- res->name = dev->name;
- reg = PCI_BASE_ADDRESS_0 + (pos << 2);
- pci_read_config_dword(dev, reg, &l);
- pci_write_config_dword(dev, reg, ~0);
- pci_read_config_dword(dev, reg, &sz);
- pci_write_config_dword(dev, reg, l);
- if (!sz || sz == 0xffffffff)
- continue;
- if (l == 0xffffffff)
- l = 0;
- if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
- res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
- res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;
- sz = pci_size(sz, PCI_BASE_ADDRESS_MEM_MASK);
- } else {
- res->start = l & PCI_BASE_ADDRESS_IO_MASK;
- res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK;
- sz = pci_size(sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff);
- }
- res->end = res->start + (unsigned long) sz;
- res->flags |= pci_calc_resource_flags(l);
- if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
- == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
- pci_read_config_dword(dev, reg+4, &l);
- next++;
-#if BITS_PER_LONG == 64
- res->start |= ((unsigned long) l) << 32;
- res->end = res->start + sz;
- pci_write_config_dword(dev, reg+4, ~0);
- pci_read_config_dword(dev, reg+4, &sz);
- pci_write_config_dword(dev, reg+4, l);
- if (~sz)
- res->end = res->start + 0xffffffff +
- (((unsigned long) ~sz) << 32);
-#else
- if (l) {
- printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", dev->slot_name);
- res->start = 0;
- res->flags = 0;
- continue;
- }
-#endif
- }
- }
- if (rom) {
- dev->rom_base_reg = rom;
- res = &dev->resource[PCI_ROM_RESOURCE];
- pci_read_config_dword(dev, rom, &l);
- pci_write_config_dword(dev, rom, ~PCI_ROM_ADDRESS_ENABLE);
- pci_read_config_dword(dev, rom, &sz);
- pci_write_config_dword(dev, rom, l);
- if (l == 0xffffffff)
- l = 0;
- if (sz && sz != 0xffffffff) {
- res->flags = (l & PCI_ROM_ADDRESS_ENABLE) |
- IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
- res->start = l & PCI_ROM_ADDRESS_MASK;
- sz = pci_size(sz, PCI_ROM_ADDRESS_MASK);
- res->end = res->start + (unsigned long) sz;
- }
- res->name = dev->name;
- }
-}
-
-void __devinit pci_read_bridge_bases(struct pci_bus *child)
-{
- struct pci_dev *dev = child->self;
- u8 io_base_lo, io_limit_lo;
- u16 mem_base_lo, mem_limit_lo;
- unsigned long base, limit;
- struct resource *res;
- int i;
-
- if (!dev) /* It's a host bus, nothing to read */
- return;
-
- for(i=0; i<3; i++)
- child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
-
- res = child->resource[0];
- pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
- pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
- base = (io_base_lo & PCI_IO_RANGE_MASK) << 8;
- limit = (io_limit_lo & PCI_IO_RANGE_MASK) << 8;
-
- if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
- u16 io_base_hi, io_limit_hi;
- pci_read_config_word(dev, PCI_IO_BASE_UPPER16, &io_base_hi);
- pci_read_config_word(dev, PCI_IO_LIMIT_UPPER16, &io_limit_hi);
- base |= (io_base_hi << 16);
- limit |= (io_limit_hi << 16);
- }
-
- if (base && base <= limit) {
- res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
- res->start = base;
- res->end = limit + 0xfff;
- res->name = child->name;
- } else {
- /*
- * Ugh. We don't know enough about this bridge. Just assume
- * that it's entirely transparent.
- */
- printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 0);
- child->resource[0] = child->parent->resource[0];
- }
-
- res = child->resource[1];
- pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
- pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo);
- base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
- limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
- if (base && base <= limit) {
- res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
- res->start = base;
- res->end = limit + 0xfffff;
- res->name = child->name;
- } else {
- /* See comment above. Same thing */
- printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 1);
- child->resource[1] = child->parent->resource[1];
- }
-
- res = child->resource[2];
- pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
- pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo);
- base = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
- limit = (mem_limit_lo & PCI_PREF_RANGE_MASK) << 16;
-
- if ((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
- u32 mem_base_hi, mem_limit_hi;
- pci_read_config_dword(dev, PCI_PREF_BASE_UPPER32, &mem_base_hi);
- pci_read_config_dword(dev, PCI_PREF_LIMIT_UPPER32, &mem_limit_hi);
-#if BITS_PER_LONG == 64
- base |= ((long) mem_base_hi) << 32;
- limit |= ((long) mem_limit_hi) << 32;
-#else
- if (mem_base_hi || mem_limit_hi) {
- printk(KERN_ERR "PCI: Unable to handle 64-bit address space for %s\n", child->name);
- return;
- }
-#endif
- }
- if (base && base <= limit) {
- res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH;
- res->start = base;
- res->end = limit + 0xfffff;
- res->name = child->name;
- } else {
- /* See comments above */
- printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 2);
- child->resource[2] = child->parent->resource[2];
- }
-}
-
-static struct pci_bus * __devinit pci_alloc_bus(void)
-{
- struct pci_bus *b;
-
- b = kmalloc(sizeof(*b), GFP_KERNEL);
- if (b) {
- memset(b, 0, sizeof(*b));
- INIT_LIST_HEAD(&b->children);
- INIT_LIST_HEAD(&b->devices);
- }
- return b;
-}
-
-struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, 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;
-
- /*
- * 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.. */
- for (i = 0; i < 4; i++)
- child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
-
- return child;
-}
-
-unsigned int __devinit pci_do_scan_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
- * be handled by the bridge driver itself.
- *
- * We need to process bridges in two passes -- first we scan those
- * already configured by the BIOS and after we are done with all of
- * them, we proceed to assigning numbers to the remaining buses in
- * order to avoid overlaps between old and new bus numbers.
- */
-static int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass)
-{
- unsigned int buses;
- unsigned short cr;
- struct pci_bus *child;
- int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
-
- pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
- DBG("Scanning behind PCI bridge %s, config %06x, pass %d\n", dev->slot_name, buses & 0xffffff, pass);
- if ((buses & 0xffff00) && !pcibios_assign_all_busses()) {
- /*
- * Bus already configured by firmware, process it in the first
- * pass and just note the configuration.
- */
- if (pass)
- return max;
- child = pci_add_new_bus(bus, dev, 0);
- child->primary = buses & 0xFF;
- child->secondary = (buses >> 8) & 0xFF;
- child->subordinate = (buses >> 16) & 0xFF;
- child->number = child->secondary;
- if (!is_cardbus) {
- unsigned int cmax = pci_do_scan_bus(child);
- if (cmax > max) max = cmax;
- } else {
- unsigned int cmax = child->subordinate;
- if (cmax > max) max = cmax;
- }
- } else {
- /*
- * We need to assign a number to this bus which we always
- * do in the second pass. We also keep all address decoders
- * on the bridge disabled during scanning. FIXME: Why?
- */
- if (!pass)
- return max;
- pci_read_config_word(dev, PCI_COMMAND, &cr);
- pci_write_config_word(dev, PCI_COMMAND, 0x0000);
- pci_write_config_word(dev, PCI_STATUS, 0xffff);
-
- child = pci_add_new_bus(bus, dev, ++max);
- buses = (buses & 0xff000000)
- | ((unsigned int)(child->primary) << 0)
- | ((unsigned int)(child->secondary) << 8)
- | ((unsigned int)(child->subordinate) << 16);
- /*
- * 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);
- } else {
- /*
- * For CardBus bridges, we leave 4 bus numbers
- * as cards with a PCI-to-PCI bridge can be
- * inserted later.
- */
- max += 3;
- }
- /*
- * Set the subordinate bus number to its real value.
- */
- child->subordinate = max;
- pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
- pci_write_config_word(dev, PCI_COMMAND, cr);
- }
- sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number);
-
- return max;
-}
-
-/*
- * Read interrupt line and base address registers.
- * The architecture-dependent code can tweak these, of course.
- */
-static void pci_read_irq(struct pci_dev *dev)
-{
- unsigned char irq;
-
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq);
- if (irq)
- pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
- dev->irq = irq;
-}
-
-/**
- * pci_setup_device - fill in class and map information of a device
- * @dev: the device structure to fill
- *
- * Initialize the device structure with information about the device's
- * vendor,class,memory and IO-space addresses,IRQ lines etc.
- * Called at initialisation of the PCI subsystem and by CardBus services.
- * Returns 0 on success and -1 if unknown type of device (not normal, bridge
- * or CardBus).
- */
-int pci_setup_device(struct pci_dev * dev)
-{
- u32 class;
-
- sprintf(dev->slot_name, "%02x:%02x.%d", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
- sprintf(dev->name, "PCI device %04x:%04x", dev->vendor, dev->device);
-
- pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
- class >>= 8; /* upper 3 bytes */
- 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);
-
- /* "Unknown power state" */
- dev->current_state = 4;
-
- switch (dev->hdr_type) { /* header type */
- case PCI_HEADER_TYPE_NORMAL: /* standard header */
- if (class == PCI_CLASS_BRIDGE_PCI)
- goto bad;
- pci_read_irq(dev);
- pci_read_bases(dev, 6, PCI_ROM_ADDRESS);
- pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);
- pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device);
- break;
-
- case PCI_HEADER_TYPE_BRIDGE: /* bridge header */
- if (class != PCI_CLASS_BRIDGE_PCI)
- goto bad;
- pci_read_bases(dev, 2, PCI_ROM_ADDRESS1);
- break;
-
- case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */
- if (class != PCI_CLASS_BRIDGE_CARDBUS)
- goto bad;
- pci_read_irq(dev);
- pci_read_bases(dev, 1, 0);
- pci_read_config_word(dev, PCI_CB_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);
- pci_read_config_word(dev, PCI_CB_SUBSYSTEM_ID, &dev->subsystem_device);
- break;
-
- default: /* unknown header */
- printk(KERN_ERR "PCI: device %s has unknown header type %02x, ignoring.\n",
- dev->slot_name, dev->hdr_type);
- return -1;
-
- bad:
- printk(KERN_ERR "PCI: %s: class %x doesn't match header type %02x. Ignoring class.\n",
- dev->slot_name, class, dev->hdr_type);
- dev->class = PCI_CLASS_NOT_DEFINED;
- }
-
- /* We found a fine healthy device, go go go... */
- return 0;
-}
-
-/*
- * 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)
-{
- struct pci_dev *dev;
- u32 l;
-
- if (pci_read_config_dword(temp, 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);
- if (!dev)
- return NULL;
-
- memcpy(dev, temp, sizeof(*dev));
- dev->vendor = l & 0xffff;
- dev->device = (l >> 16) & 0xffff;
-
- /* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
- set this higher, assuming the system even supports it. */
- dev->dma_mask = 0xffffffff;
- if (pci_setup_device(dev) < 0) {
- kfree(dev);
- return NULL;
- }
-
- /* now put in global tree */
- strcpy(dev->dev.name,dev->name);
- strcpy(dev->dev.bus_id,dev->slot_name);
-
- device_register(&dev->dev);
- return dev;
-}
-
-struct pci_dev * __devinit pci_scan_slot(struct pci_dev *temp)
-{
- 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;
-
- 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;
-
- dev = pci_scan_device(temp);
- if (!dev)
- continue;
- pci_name_device(dev);
- if (!func) {
- is_multi = hdr_type & 0x80;
- first_dev = dev;
- }
-
- /*
- * Link the device to both the global PCI device chain and
- * the per-bus list of devices.
- */
- list_add_tail(&dev->global_list, &pci_devices);
- list_add_tail(&dev->bus_list, &bus->devices);
-
- /* Fix up broken headers */
- pci_fixup_device(PCI_FIXUP_HEADER, dev);
- }
- return first_dev;
-}
-
-unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
-{
- unsigned int devfn, max, pass;
- struct list_head *ln;
- struct pci_dev *dev, dev0;
-
- DBG("Scanning bus %02x\n", bus->number);
- max = bus->secondary;
-
- /* Create a device template */
- memset(&dev0, 0, sizeof(dev0));
- dev0.bus = bus;
- dev0.sysdata = bus->sysdata;
- dev0.dev.parent = bus->dev;
- dev0.dev.driver = &pci_device_driver;
-
- /* Go find them, Rover! */
- for (devfn = 0; devfn < 0x100; devfn += 8) {
- dev0.devfn = devfn;
- pci_scan_slot(&dev0);
- }
-
- /*
- * 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);
- 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)
- max = pci_scan_bridge(bus, dev, max, pass);
- }
-
- /*
- * 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("Bus scan for %02x returning with max=%02x\n", bus->number, max);
- return max;
-}
-
-int __devinit pci_bus_exists(const struct list_head *list, int nr)
-{
- const struct list_head *l;
-
- for(l=list->next; l != list; l = l->next) {
- const struct pci_bus *b = pci_bus_b(l);
- if (b->number == nr || pci_bus_exists(&b->children, nr))
- return 1;
- }
- return 0;
-}
-
-struct pci_bus * __devinit pci_alloc_primary_bus(int bus)
-{
- struct pci_bus *b;
-
- if (pci_bus_exists(&pci_root_buses, bus)) {
- /* If we already got to this bus through a different bridge, ignore it */
- DBG("PCI: Bus %02x already known\n", bus);
- return NULL;
- }
-
- b = pci_alloc_bus();
- if (!b)
- return NULL;
- list_add_tail(&b->node, &pci_root_buses);
-
- b->dev = kmalloc(sizeof(*(b->dev)),GFP_KERNEL);
- memset(b->dev,0,sizeof(*(b->dev)));
- sprintf(b->dev->bus_id,"pci%d",bus);
- strcpy(b->dev->name,"Host/PCI Bridge");
- device_register(b->dev);
-
- b->number = b->secondary = bus;
- b->resource[0] = &ioport_resource;
- b->resource[1] = &iomem_resource;
- return b;
-}
-
-struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata)
-{
- struct pci_bus *b = pci_alloc_primary_bus(bus);
- if (b) {
- b->sysdata = sysdata;
- b->ops = ops;
- b->subordinate = pci_do_scan_bus(b);
- }
- return b;
-}
-
-#ifdef CONFIG_PM
-
-/*
- * PCI Power management..
- *
- * This needs to be done centralized, so that we power manage PCI
- * devices in the right order: we should not shut down PCI bridges
- * before we've shut down the devices behind them, and we should
- * not wake up devices before we've woken up the bridge to the
- * device.. Eh?
- *
- * We do not touch devices that don't have a driver that exports
- * a suspend/resume function. That is just too dangerous. If the default
- * PCI suspend/resume functions work for a device, the driver can
- * easily implement them (ie just have a suspend function that calls
- * the pci_set_power_state() function).
- */
-
-static int pci_pm_save_state_device(struct pci_dev *dev, u32 state)
-{
- int error = 0;
- if (dev) {
- struct pci_driver *driver = dev->driver;
- if (driver && driver->save_state)
- error = driver->save_state(dev,state);
- }
- return error;
-}
-
-static int pci_pm_suspend_device(struct pci_dev *dev, u32 state)
-{
- int error = 0;
- if (dev) {
- struct pci_driver *driver = dev->driver;
- if (driver && driver->suspend)
- error = driver->suspend(dev,state);
- }
- return error;
-}
-
-static int pci_pm_resume_device(struct pci_dev *dev)
-{
- int error = 0;
- if (dev) {
- struct pci_driver *driver = dev->driver;
- if (driver && driver->resume)
- error = driver->resume(dev);
- }
- return error;
-}
-
-static int pci_pm_save_state_bus(struct pci_bus *bus, u32 state)
-{
- struct list_head *list;
- int error = 0;
-
- list_for_each(list, &bus->children) {
- error = pci_pm_save_state_bus(pci_bus_b(list),state);
- if (error) return error;
- }
- list_for_each(list, &bus->devices) {
- error = pci_pm_save_state_device(pci_dev_b(list),state);
- if (error) return error;
- }
- return 0;
-}
-
-static int pci_pm_suspend_bus(struct pci_bus *bus, u32 state)
-{
- struct list_head *list;
-
- /* Walk the bus children list */
- list_for_each(list, &bus->children)
- pci_pm_suspend_bus(pci_bus_b(list),state);
-
- /* Walk the device children list */
- list_for_each(list, &bus->devices)
- pci_pm_suspend_device(pci_dev_b(list),state);
- return 0;
-}
-
-static int pci_pm_resume_bus(struct pci_bus *bus)
-{
- struct list_head *list;
-
- /* Walk the device children list */
- list_for_each(list, &bus->devices)
- pci_pm_resume_device(pci_dev_b(list));
-
- /* And then walk the bus children */
- list_for_each(list, &bus->children)
- pci_pm_resume_bus(pci_bus_b(list));
- return 0;
-}
-
-static int pci_pm_save_state(u32 state)
-{
- struct list_head *list;
- struct pci_bus *bus;
- int error = 0;
-
- list_for_each(list, &pci_root_buses) {
- bus = pci_bus_b(list);
- error = pci_pm_save_state_bus(bus,state);
- if (!error)
- error = pci_pm_save_state_device(bus->self,state);
- }
- return error;
-}
-
-static int pci_pm_suspend(u32 state)
-{
- struct list_head *list;
- struct pci_bus *bus;
-
- list_for_each(list, &pci_root_buses) {
- bus = pci_bus_b(list);
- pci_pm_suspend_bus(bus,state);
- pci_pm_suspend_device(bus->self,state);
- }
- return 0;
-}
-
-static int pci_pm_resume(void)
-{
- struct list_head *list;
- struct pci_bus *bus;
-
- list_for_each(list, &pci_root_buses) {
- bus = pci_bus_b(list);
- pci_pm_resume_device(bus->self);
- pci_pm_resume_bus(bus);
- }
- return 0;
-}
-
-static int
-pci_pm_callback(struct pm_dev *pm_device, pm_request_t rqst, void *data)
-{
- int error = 0;
-
- switch (rqst) {
- case PM_SAVE_STATE:
- error = pci_pm_save_state((unsigned long)data);
- break;
- case PM_SUSPEND:
- error = pci_pm_suspend((unsigned long)data);
- break;
- case PM_RESUME:
- error = pci_pm_resume();
- break;
- default: break;
- }
- return error;
-}
-
-#endif
-
-/*
- * Pool allocator ... wraps the pci_alloc_consistent page allocator, so
- * small blocks are easily used by drivers for bus mastering controllers.
- * This should probably be sharing the guts of the slab allocator.
- */
-
-struct pci_pool { /* the pool */
- struct list_head page_list;
- spinlock_t lock;
- size_t blocks_per_page;
- size_t size;
- struct pci_dev *dev;
- size_t allocation;
- char name [32];
- wait_queue_head_t waitq;
-};
-
-struct pci_page { /* cacheable header for 'allocation' bytes */
- struct list_head page_list;
- void *vaddr;
- dma_addr_t dma;
- unsigned long bitmap [0];
-};
-
-#define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000)
-#define POOL_POISON_BYTE 0xa7
-
-
-/**
- * pci_pool_create - Creates a pool of pci consistent memory blocks, for dma.
- * @name: name of pool, for diagnostics
- * @pdev: pci device that will be doing the DMA
- * @size: size of the blocks in this pool.
- * @align: alignment requirement for blocks; must be a power of two
- * @allocation: returned blocks won't cross this boundary (or zero)
- * @mem_flags: SLAB_* flags.
- *
- * Returns a pci allocation pool with the requested characteristics, or
- * null if one can't be created. Given one of these pools, pci_pool_alloc()
- * may be used to allocate memory. Such memory will all have "consistent"
- * DMA mappings, accessible by the device and its driver without using
- * cache flushing primitives. The actual size of blocks allocated may be
- * larger than requested because of alignment.
- *
- * If allocation is nonzero, objects returned from pci_pool_alloc() won't
- * cross that size boundary. This is useful for devices which have
- * addressing restrictions on individual DMA transfers, such as not crossing
- * boundaries of 4KBytes.
- */
-struct pci_pool *
-pci_pool_create (const char *name, struct pci_dev *pdev,
- size_t size, size_t align, size_t allocation, int mem_flags)
-{
- struct pci_pool *retval;
-
- if (align == 0)
- align = 1;
- if (size == 0)
- return 0;
- else if (size < align)
- size = align;
- else if ((size % align) != 0) {
- size += align + 1;
- size &= ~(align - 1);
- }
-
- if (allocation == 0) {
- if (PAGE_SIZE < size)
- allocation = size;
- else
- allocation = PAGE_SIZE;
- // FIXME: round up for less fragmentation
- } else if (allocation < size)
- return 0;
-
- if (!(retval = kmalloc (sizeof *retval, mem_flags)))
- return retval;
-
- strncpy (retval->name, name, sizeof retval->name);
- retval->name [sizeof retval->name - 1] = 0;
-
- retval->dev = pdev;
- INIT_LIST_HEAD (&retval->page_list);
- spin_lock_init (&retval->lock);
- retval->size = size;
- retval->allocation = allocation;
- retval->blocks_per_page = allocation / size;
- init_waitqueue_head (&retval->waitq);
-
- return retval;
-}
-
-
-static struct pci_page *
-pool_alloc_page (struct pci_pool *pool, int mem_flags)
-{
- struct pci_page *page;
- int mapsize;
-
- mapsize = pool->blocks_per_page;
- mapsize = (mapsize + BITS_PER_LONG - 1) / BITS_PER_LONG;
- mapsize *= sizeof (long);
-
- page = (struct pci_page *) kmalloc (mapsize + sizeof *page, mem_flags);
- if (!page)
- return 0;
- page->vaddr = pci_alloc_consistent (pool->dev,
- pool->allocation,
- &page->dma);
- if (page->vaddr) {
- memset (page->bitmap, 0xff, mapsize); // bit set == free
-#ifdef CONFIG_DEBUG_SLAB
- memset (page->vaddr, POOL_POISON_BYTE, pool->allocation);
-#endif
- list_add (&page->page_list, &pool->page_list);
- } else {
- kfree (page);
- page = 0;
- }
- return page;
-}
-
-
-static inline int
-is_page_busy (int blocks, unsigned long *bitmap)
-{
- while (blocks > 0) {
- if (*bitmap++ != ~0UL)
- return 1;
- blocks -= BITS_PER_LONG;
- }
- return 0;
-}
-
-static void
-pool_free_page (struct pci_pool *pool, struct pci_page *page)
-{
- dma_addr_t dma = page->dma;
-
-#ifdef CONFIG_DEBUG_SLAB
- memset (page->vaddr, POOL_POISON_BYTE, pool->allocation);
-#endif
- pci_free_consistent (pool->dev, pool->allocation, page->vaddr, dma);
- list_del (&page->page_list);
- kfree (page);
-}
-
-
-/**
- * pci_pool_destroy - destroys a pool of pci memory blocks.
- * @pool: pci pool that will be destroyed
- *
- * Caller guarantees that no more memory from the pool is in use,
- * and that nothing will try to use the pool after this call.
- */
-void
-pci_pool_destroy (struct pci_pool *pool)
-{
- unsigned long flags;
-
- spin_lock_irqsave (&pool->lock, flags);
- while (!list_empty (&pool->page_list)) {
- struct pci_page *page;
- page = list_entry (pool->page_list.next,
- struct pci_page, page_list);
- if (is_page_busy (pool->blocks_per_page, page->bitmap)) {
- printk (KERN_ERR "pci_pool_destroy %s/%s, %p busy\n",
- pool->dev ? pool->dev->slot_name : NULL,
- pool->name, page->vaddr);
- /* leak the still-in-use consistent memory */
- list_del (&page->page_list);
- kfree (page);
- } else
- pool_free_page (pool, page);
- }
- spin_unlock_irqrestore (&pool->lock, flags);
- kfree (pool);
-}
-
-
-/**
- * pci_pool_alloc - get a block of consistent memory
- * @pool: pci pool that will produce the block
- * @mem_flags: SLAB_KERNEL or SLAB_ATOMIC
- * @handle: pointer to dma address of block
- *
- * This returns the kernel virtual address of a currently unused block,
- * and reports its dma address through the handle.
- * If such a memory block can't be allocated, null is returned.
- */
-void *
-pci_pool_alloc (struct pci_pool *pool, int mem_flags, dma_addr_t *handle)
-{
- unsigned long flags;
- struct list_head *entry;
- struct pci_page *page;
- int map, block;
- size_t offset;
- void *retval;
-
-restart:
- spin_lock_irqsave (&pool->lock, flags);
- list_for_each (entry, &pool->page_list) {
- int i;
- page = list_entry (entry, struct pci_page, page_list);
- /* only cachable accesses here ... */
- for (map = 0, i = 0;
- i < pool->blocks_per_page;
- i += BITS_PER_LONG, map++) {
- if (page->bitmap [map] == 0)
- continue;
- block = ffz (~ page->bitmap [map]);
- if ((i + block) < pool->blocks_per_page) {
- clear_bit (block, &page->bitmap [map]);
- offset = (BITS_PER_LONG * map) + block;
- offset *= pool->size;
- goto ready;
- }
- }
- }
- if (!(page = pool_alloc_page (pool, mem_flags))) {
- if (mem_flags == SLAB_KERNEL) {
- DECLARE_WAITQUEUE (wait, current);
-
- current->state = TASK_INTERRUPTIBLE;
- add_wait_queue (&pool->waitq, &wait);
- spin_unlock_irqrestore (&pool->lock, flags);
-
- schedule_timeout (POOL_TIMEOUT_JIFFIES);
-
- current->state = TASK_RUNNING;
- remove_wait_queue (&pool->waitq, &wait);
- goto restart;
- }
- retval = 0;
- goto done;
- }
-
- clear_bit (0, &page->bitmap [0]);
- offset = 0;
-ready:
- retval = offset + page->vaddr;
- *handle = offset + page->dma;
-done:
- spin_unlock_irqrestore (&pool->lock, flags);
- return retval;
-}
-
-
-static struct pci_page *
-pool_find_page (struct pci_pool *pool, dma_addr_t dma)
-{
- unsigned long flags;
- struct list_head *entry;
- struct pci_page *page;
-
- spin_lock_irqsave (&pool->lock, flags);
- list_for_each (entry, &pool->page_list) {
- page = list_entry (entry, struct pci_page, page_list);
- if (dma < page->dma)
- continue;
- if (dma < (page->dma + pool->allocation))
- goto done;
- }
- page = 0;
-done:
- spin_unlock_irqrestore (&pool->lock, flags);
- return page;
-}
-
-
-/**
- * pci_pool_free - put block back into pci pool
- * @pool: the pci pool holding the block
- * @vaddr: virtual address of block
- * @dma: dma address of block
- *
- * Caller promises neither device nor driver will again touch this block
- * unless it is first re-allocated.
- */
-void
-pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t dma)
-{
- struct pci_page *page;
- unsigned long flags;
- int map, block;
-
- if ((page = pool_find_page (pool, dma)) == 0) {
- printk (KERN_ERR "pci_pool_free %s/%s, %p/%lx (bad dma)\n",
- pool->dev ? pool->dev->slot_name : NULL,
- pool->name, vaddr, (unsigned long) dma);
- return;
- }
-
- block = dma - page->dma;
- block /= pool->size;
- map = block / BITS_PER_LONG;
- block %= BITS_PER_LONG;
-
-#ifdef CONFIG_DEBUG_SLAB
- if (((dma - page->dma) + (void *)page->vaddr) != vaddr) {
- printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%lx\n",
- pool->dev ? pool->dev->slot_name : NULL,
- pool->name, vaddr, (unsigned long) dma);
- return;
- }
- if (page->bitmap [map] & (1UL << block)) {
- printk (KERN_ERR "pci_pool_free %s/%s, dma %x already free\n",
- pool->dev ? pool->dev->slot_name : NULL,
- pool->name, dma);
- return;
- }
- memset (vaddr, POOL_POISON_BYTE, pool->size);
-#endif
-
- spin_lock_irqsave (&pool->lock, flags);
- set_bit (block, &page->bitmap [map]);
- if (waitqueue_active (&pool->waitq))
- wake_up (&pool->waitq);
- /*
- * Resist a temptation to do
- * if (!is_page_busy(bpp, page->bitmap)) pool_free_page(pool, page);
- * it is not interrupt safe. Better have empty pages hang around.
- */
- spin_unlock_irqrestore (&pool->lock, flags);
-}
-
static int __devinit pci_init(void)
{
@@ -2034,10 +560,6 @@ static int __devinit pci_init(void)
pci_for_each_dev(dev) {
pci_fixup_device(PCI_FIXUP_FINAL, dev);
}
-
-#ifdef CONFIG_PM
- pm_register(PM_PCI_DEV, 0, pci_pm_callback);
-#endif
return 0;
}
@@ -2060,51 +582,19 @@ subsys_initcall(pci_init);
__setup("pci=", pci_setup);
-EXPORT_SYMBOL(pci_read_config_byte);
-EXPORT_SYMBOL(pci_read_config_word);
-EXPORT_SYMBOL(pci_read_config_dword);
-EXPORT_SYMBOL(pci_write_config_byte);
-EXPORT_SYMBOL(pci_write_config_word);
-EXPORT_SYMBOL(pci_write_config_dword);
-EXPORT_SYMBOL(pci_devices);
-EXPORT_SYMBOL(pci_root_buses);
EXPORT_SYMBOL(pci_enable_device);
EXPORT_SYMBOL(pci_disable_device);
EXPORT_SYMBOL(pci_find_capability);
EXPORT_SYMBOL(pci_release_regions);
EXPORT_SYMBOL(pci_request_regions);
-EXPORT_SYMBOL(pci_find_class);
-EXPORT_SYMBOL(pci_find_device);
-EXPORT_SYMBOL(pci_find_slot);
-EXPORT_SYMBOL(pci_find_subsys);
EXPORT_SYMBOL(pci_set_master);
EXPORT_SYMBOL(pci_set_mwi);
EXPORT_SYMBOL(pci_clear_mwi);
EXPORT_SYMBOL(pci_set_dma_mask);
EXPORT_SYMBOL(pci_dac_set_dma_mask);
EXPORT_SYMBOL(pci_assign_resource);
-EXPORT_SYMBOL(pci_register_driver);
-EXPORT_SYMBOL(pci_unregister_driver);
-EXPORT_SYMBOL(pci_dev_driver);
-EXPORT_SYMBOL(pci_match_device);
EXPORT_SYMBOL(pci_find_parent_resource);
-#ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(pci_setup_device);
-EXPORT_SYMBOL(pci_insert_device);
-EXPORT_SYMBOL(pci_remove_device);
-EXPORT_SYMBOL(pci_announce_device_to_drivers);
-EXPORT_SYMBOL(pci_add_new_bus);
-EXPORT_SYMBOL(pci_do_scan_bus);
-EXPORT_SYMBOL(pci_scan_slot);
-#ifdef CONFIG_PROC_FS
-EXPORT_SYMBOL(pci_proc_attach_device);
-EXPORT_SYMBOL(pci_proc_detach_device);
-EXPORT_SYMBOL(pci_proc_attach_bus);
-EXPORT_SYMBOL(pci_proc_detach_bus);
-#endif
-#endif
-
EXPORT_SYMBOL(pci_set_power_state);
EXPORT_SYMBOL(pci_save_state);
EXPORT_SYMBOL(pci_restore_state);
@@ -2126,11 +616,3 @@ EXPORT_SYMBOL(pcibios_find_device);
EXPORT_SYMBOL(isa_dma_bridge_buggy);
EXPORT_SYMBOL(pci_pci_problems);
-
-/* Pool allocator */
-
-EXPORT_SYMBOL (pci_pool_create);
-EXPORT_SYMBOL (pci_pool_destroy);
-EXPORT_SYMBOL (pci_pool_alloc);
-EXPORT_SYMBOL (pci_pool_free);
-
diff --git a/drivers/pci/pool.c b/drivers/pci/pool.c
new file mode 100644
index 000000000000..700d2abbe278
--- /dev/null
+++ b/drivers/pci/pool.c
@@ -0,0 +1,335 @@
+#include <linux/pci.h>
+#include <linux/module.h>
+
+/*
+ * Pool allocator ... wraps the pci_alloc_consistent page allocator, so
+ * small blocks are easily used by drivers for bus mastering controllers.
+ * This should probably be sharing the guts of the slab allocator.
+ */
+
+struct pci_pool { /* the pool */
+ struct list_head page_list;
+ spinlock_t lock;
+ size_t blocks_per_page;
+ size_t size;
+ struct pci_dev *dev;
+ size_t allocation;
+ char name [32];
+ wait_queue_head_t waitq;
+};
+
+struct pci_page { /* cacheable header for 'allocation' bytes */
+ struct list_head page_list;
+ void *vaddr;
+ dma_addr_t dma;
+ unsigned long bitmap [0];
+};
+
+#define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000)
+#define POOL_POISON_BYTE 0xa7
+
+
+/**
+ * pci_pool_create - Creates a pool of pci consistent memory blocks, for dma.
+ * @name: name of pool, for diagnostics
+ * @pdev: pci device that will be doing the DMA
+ * @size: size of the blocks in this pool.
+ * @align: alignment requirement for blocks; must be a power of two
+ * @allocation: returned blocks won't cross this boundary (or zero)
+ * @mem_flags: SLAB_* flags.
+ *
+ * Returns a pci allocation pool with the requested characteristics, or
+ * null if one can't be created. Given one of these pools, pci_pool_alloc()
+ * may be used to allocate memory. Such memory will all have "consistent"
+ * DMA mappings, accessible by the device and its driver without using
+ * cache flushing primitives. The actual size of blocks allocated may be
+ * larger than requested because of alignment.
+ *
+ * If allocation is nonzero, objects returned from pci_pool_alloc() won't
+ * cross that size boundary. This is useful for devices which have
+ * addressing restrictions on individual DMA transfers, such as not crossing
+ * boundaries of 4KBytes.
+ */
+struct pci_pool *
+pci_pool_create (const char *name, struct pci_dev *pdev,
+ size_t size, size_t align, size_t allocation, int mem_flags)
+{
+ struct pci_pool *retval;
+
+ if (align == 0)
+ align = 1;
+ if (size == 0)
+ return 0;
+ else if (size < align)
+ size = align;
+ else if ((size % align) != 0) {
+ size += align + 1;
+ size &= ~(align - 1);
+ }
+
+ if (allocation == 0) {
+ if (PAGE_SIZE < size)
+ allocation = size;
+ else
+ allocation = PAGE_SIZE;
+ // FIXME: round up for less fragmentation
+ } else if (allocation < size)
+ return 0;
+
+ if (!(retval = kmalloc (sizeof *retval, mem_flags)))
+ return retval;
+
+ strncpy (retval->name, name, sizeof retval->name);
+ retval->name [sizeof retval->name - 1] = 0;
+
+ retval->dev = pdev;
+ INIT_LIST_HEAD (&retval->page_list);
+ spin_lock_init (&retval->lock);
+ retval->size = size;
+ retval->allocation = allocation;
+ retval->blocks_per_page = allocation / size;
+ init_waitqueue_head (&retval->waitq);
+
+ return retval;
+}
+
+
+static struct pci_page *
+pool_alloc_page (struct pci_pool *pool, int mem_flags)
+{
+ struct pci_page *page;
+ int mapsize;
+
+ mapsize = pool->blocks_per_page;
+ mapsize = (mapsize + BITS_PER_LONG - 1) / BITS_PER_LONG;
+ mapsize *= sizeof (long);
+
+ page = (struct pci_page *) kmalloc (mapsize + sizeof *page, mem_flags);
+ if (!page)
+ return 0;
+ page->vaddr = pci_alloc_consistent (pool->dev,
+ pool->allocation,
+ &page->dma);
+ if (page->vaddr) {
+ memset (page->bitmap, 0xff, mapsize); // bit set == free
+#ifdef CONFIG_DEBUG_SLAB
+ memset (page->vaddr, POOL_POISON_BYTE, pool->allocation);
+#endif
+ list_add (&page->page_list, &pool->page_list);
+ } else {
+ kfree (page);
+ page = 0;
+ }
+ return page;
+}
+
+
+static inline int
+is_page_busy (int blocks, unsigned long *bitmap)
+{
+ while (blocks > 0) {
+ if (*bitmap++ != ~0UL)
+ return 1;
+ blocks -= BITS_PER_LONG;
+ }
+ return 0;
+}
+
+static void
+pool_free_page (struct pci_pool *pool, struct pci_page *page)
+{
+ dma_addr_t dma = page->dma;
+
+#ifdef CONFIG_DEBUG_SLAB
+ memset (page->vaddr, POOL_POISON_BYTE, pool->allocation);
+#endif
+ pci_free_consistent (pool->dev, pool->allocation, page->vaddr, dma);
+ list_del (&page->page_list);
+ kfree (page);
+}
+
+
+/**
+ * pci_pool_destroy - destroys a pool of pci memory blocks.
+ * @pool: pci pool that will be destroyed
+ *
+ * Caller guarantees that no more memory from the pool is in use,
+ * and that nothing will try to use the pool after this call.
+ */
+void
+pci_pool_destroy (struct pci_pool *pool)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave (&pool->lock, flags);
+ while (!list_empty (&pool->page_list)) {
+ struct pci_page *page;
+ page = list_entry (pool->page_list.next,
+ struct pci_page, page_list);
+ if (is_page_busy (pool->blocks_per_page, page->bitmap)) {
+ printk (KERN_ERR "pci_pool_destroy %s/%s, %p busy\n",
+ pool->dev ? pool->dev->slot_name : NULL,
+ pool->name, page->vaddr);
+ /* leak the still-in-use consistent memory */
+ list_del (&page->page_list);
+ kfree (page);
+ } else
+ pool_free_page (pool, page);
+ }
+ spin_unlock_irqrestore (&pool->lock, flags);
+ kfree (pool);
+}
+
+
+/**
+ * pci_pool_alloc - get a block of consistent memory
+ * @pool: pci pool that will produce the block
+ * @mem_flags: SLAB_KERNEL or SLAB_ATOMIC
+ * @handle: pointer to dma address of block
+ *
+ * This returns the kernel virtual address of a currently unused block,
+ * and reports its dma address through the handle.
+ * If such a memory block can't be allocated, null is returned.
+ */
+void *
+pci_pool_alloc (struct pci_pool *pool, int mem_flags, dma_addr_t *handle)
+{
+ unsigned long flags;
+ struct list_head *entry;
+ struct pci_page *page;
+ int map, block;
+ size_t offset;
+ void *retval;
+
+restart:
+ spin_lock_irqsave (&pool->lock, flags);
+ list_for_each (entry, &pool->page_list) {
+ int i;
+ page = list_entry (entry, struct pci_page, page_list);
+ /* only cachable accesses here ... */
+ for (map = 0, i = 0;
+ i < pool->blocks_per_page;
+ i += BITS_PER_LONG, map++) {
+ if (page->bitmap [map] == 0)
+ continue;
+ block = ffz (~ page->bitmap [map]);
+ if ((i + block) < pool->blocks_per_page) {
+ clear_bit (block, &page->bitmap [map]);
+ offset = (BITS_PER_LONG * map) + block;
+ offset *= pool->size;
+ goto ready;
+ }
+ }
+ }
+ if (!(page = pool_alloc_page (pool, mem_flags))) {
+ if (mem_flags == SLAB_KERNEL) {
+ DECLARE_WAITQUEUE (wait, current);
+
+ current->state = TASK_INTERRUPTIBLE;
+ add_wait_queue (&pool->waitq, &wait);
+ spin_unlock_irqrestore (&pool->lock, flags);
+
+ schedule_timeout (POOL_TIMEOUT_JIFFIES);
+
+ current->state = TASK_RUNNING;
+ remove_wait_queue (&pool->waitq, &wait);
+ goto restart;
+ }
+ retval = 0;
+ goto done;
+ }
+
+ clear_bit (0, &page->bitmap [0]);
+ offset = 0;
+ready:
+ retval = offset + page->vaddr;
+ *handle = offset + page->dma;
+done:
+ spin_unlock_irqrestore (&pool->lock, flags);
+ return retval;
+}
+
+
+static struct pci_page *
+pool_find_page (struct pci_pool *pool, dma_addr_t dma)
+{
+ unsigned long flags;
+ struct list_head *entry;
+ struct pci_page *page;
+
+ spin_lock_irqsave (&pool->lock, flags);
+ list_for_each (entry, &pool->page_list) {
+ page = list_entry (entry, struct pci_page, page_list);
+ if (dma < page->dma)
+ continue;
+ if (dma < (page->dma + pool->allocation))
+ goto done;
+ }
+ page = 0;
+done:
+ spin_unlock_irqrestore (&pool->lock, flags);
+ return page;
+}
+
+
+/**
+ * pci_pool_free - put block back into pci pool
+ * @pool: the pci pool holding the block
+ * @vaddr: virtual address of block
+ * @dma: dma address of block
+ *
+ * Caller promises neither device nor driver will again touch this block
+ * unless it is first re-allocated.
+ */
+void
+pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t dma)
+{
+ struct pci_page *page;
+ unsigned long flags;
+ int map, block;
+
+ if ((page = pool_find_page (pool, dma)) == 0) {
+ printk (KERN_ERR "pci_pool_free %s/%s, %p/%lx (bad dma)\n",
+ pool->dev ? pool->dev->slot_name : NULL,
+ pool->name, vaddr, (unsigned long) dma);
+ return;
+ }
+
+ block = dma - page->dma;
+ block /= pool->size;
+ map = block / BITS_PER_LONG;
+ block %= BITS_PER_LONG;
+
+#ifdef CONFIG_DEBUG_SLAB
+ if (((dma - page->dma) + (void *)page->vaddr) != vaddr) {
+ printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%lx\n",
+ pool->dev ? pool->dev->slot_name : NULL,
+ pool->name, vaddr, (unsigned long) dma);
+ return;
+ }
+ if (page->bitmap [map] & (1UL << block)) {
+ printk (KERN_ERR "pci_pool_free %s/%s, dma %x already free\n",
+ pool->dev ? pool->dev->slot_name : NULL,
+ pool->name, dma);
+ return;
+ }
+ memset (vaddr, POOL_POISON_BYTE, pool->size);
+#endif
+
+ spin_lock_irqsave (&pool->lock, flags);
+ set_bit (block, &page->bitmap [map]);
+ if (waitqueue_active (&pool->waitq))
+ wake_up (&pool->waitq);
+ /*
+ * Resist a temptation to do
+ * if (!is_page_busy(bpp, page->bitmap)) pool_free_page(pool, page);
+ * it is not interrupt safe. Better have empty pages hang around.
+ */
+ spin_unlock_irqrestore (&pool->lock, flags);
+}
+
+
+EXPORT_SYMBOL (pci_pool_create);
+EXPORT_SYMBOL (pci_pool_destroy);
+EXPORT_SYMBOL (pci_pool_alloc);
+EXPORT_SYMBOL (pci_pool_free);
diff --git a/drivers/pci/power.c b/drivers/pci/power.c
new file mode 100644
index 000000000000..481ddbb648b9
--- /dev/null
+++ b/drivers/pci/power.c
@@ -0,0 +1,164 @@
+#include <linux/pci.h>
+#include <linux/pm.h>
+
+/*
+ * PCI Power management..
+ *
+ * This needs to be done centralized, so that we power manage PCI
+ * devices in the right order: we should not shut down PCI bridges
+ * before we've shut down the devices behind them, and we should
+ * not wake up devices before we've woken up the bridge to the
+ * device.. Eh?
+ *
+ * We do not touch devices that don't have a driver that exports
+ * a suspend/resume function. That is just too dangerous. If the default
+ * PCI suspend/resume functions work for a device, the driver can
+ * easily implement them (ie just have a suspend function that calls
+ * the pci_set_power_state() function).
+ */
+
+static int pci_pm_save_state_device(struct pci_dev *dev, u32 state)
+{
+ int error = 0;
+ if (dev) {
+ struct pci_driver *driver = dev->driver;
+ if (driver && driver->save_state)
+ error = driver->save_state(dev,state);
+ }
+ return error;
+}
+
+static int pci_pm_suspend_device(struct pci_dev *dev, u32 state)
+{
+ int error = 0;
+ if (dev) {
+ struct pci_driver *driver = dev->driver;
+ if (driver && driver->suspend)
+ error = driver->suspend(dev,state);
+ }
+ return error;
+}
+
+static int pci_pm_resume_device(struct pci_dev *dev)
+{
+ int error = 0;
+ if (dev) {
+ struct pci_driver *driver = dev->driver;
+ if (driver && driver->resume)
+ error = driver->resume(dev);
+ }
+ return error;
+}
+
+static int pci_pm_save_state_bus(struct pci_bus *bus, u32 state)
+{
+ struct list_head *list;
+ int error = 0;
+
+ list_for_each(list, &bus->children) {
+ error = pci_pm_save_state_bus(pci_bus_b(list),state);
+ if (error) return error;
+ }
+ list_for_each(list, &bus->devices) {
+ error = pci_pm_save_state_device(pci_dev_b(list),state);
+ if (error) return error;
+ }
+ return 0;
+}
+
+static int pci_pm_suspend_bus(struct pci_bus *bus, u32 state)
+{
+ struct list_head *list;
+
+ /* Walk the bus children list */
+ list_for_each(list, &bus->children)
+ pci_pm_suspend_bus(pci_bus_b(list),state);
+
+ /* Walk the device children list */
+ list_for_each(list, &bus->devices)
+ pci_pm_suspend_device(pci_dev_b(list),state);
+ return 0;
+}
+
+static int pci_pm_resume_bus(struct pci_bus *bus)
+{
+ struct list_head *list;
+
+ /* Walk the device children list */
+ list_for_each(list, &bus->devices)
+ pci_pm_resume_device(pci_dev_b(list));
+
+ /* And then walk the bus children */
+ list_for_each(list, &bus->children)
+ pci_pm_resume_bus(pci_bus_b(list));
+ return 0;
+}
+
+static int pci_pm_save_state(u32 state)
+{
+ struct list_head *list;
+ struct pci_bus *bus;
+ int error = 0;
+
+ list_for_each(list, &pci_root_buses) {
+ bus = pci_bus_b(list);
+ error = pci_pm_save_state_bus(bus,state);
+ if (!error)
+ error = pci_pm_save_state_device(bus->self,state);
+ }
+ return error;
+}
+
+static int pci_pm_suspend(u32 state)
+{
+ struct list_head *list;
+ struct pci_bus *bus;
+
+ list_for_each(list, &pci_root_buses) {
+ bus = pci_bus_b(list);
+ pci_pm_suspend_bus(bus,state);
+ pci_pm_suspend_device(bus->self,state);
+ }
+ return 0;
+}
+
+static int pci_pm_resume(void)
+{
+ struct list_head *list;
+ struct pci_bus *bus;
+
+ list_for_each(list, &pci_root_buses) {
+ bus = pci_bus_b(list);
+ pci_pm_resume_device(bus->self);
+ pci_pm_resume_bus(bus);
+ }
+ return 0;
+}
+
+static int
+pci_pm_callback(struct pm_dev *pm_device, pm_request_t rqst, void *data)
+{
+ int error = 0;
+
+ switch (rqst) {
+ case PM_SAVE_STATE:
+ error = pci_pm_save_state((unsigned long)data);
+ break;
+ case PM_SUSPEND:
+ error = pci_pm_suspend((unsigned long)data);
+ break;
+ case PM_RESUME:
+ error = pci_pm_resume();
+ break;
+ default: break;
+ }
+ return error;
+}
+
+static int __init pci_pm_init(void)
+{
+ pm_register(PM_PCI_DEV, 0, pci_pm_callback);
+ return 0;
+}
+
+subsys_initcall(pci_pm_init);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
new file mode 100644
index 000000000000..00a357b366a4
--- /dev/null
+++ b/drivers/pci/probe.c
@@ -0,0 +1,603 @@
+/*
+ * probe.c - PCI detection and setup code
+ */
+
+#include <linux/pci.h>
+#include <linux/module.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+LIST_HEAD(pci_root_buses);
+LIST_HEAD(pci_devices);
+
+extern struct device_driver pci_device_driver;
+
+/*
+ * Translate the low bits of the PCI base
+ * to the resource type
+ */
+static inline unsigned int pci_calc_resource_flags(unsigned int flags)
+{
+ if (flags & PCI_BASE_ADDRESS_SPACE_IO)
+ return IORESOURCE_IO;
+
+ if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH)
+ return IORESOURCE_MEM | IORESOURCE_PREFETCH;
+
+ return IORESOURCE_MEM;
+}
+
+/*
+ * Find the extent of a PCI decode..
+ */
+static u32 pci_size(u32 base, unsigned long mask)
+{
+ u32 size = mask & base; /* Find the significant bits */
+ size = size & ~(size-1); /* Get the lowest of them to find the decode size */
+ return size-1; /* extent = size - 1 */
+}
+
+static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
+{
+ unsigned int pos, reg, next;
+ u32 l, sz;
+ struct resource *res;
+
+ for(pos=0; pos<howmany; pos = next) {
+ next = pos+1;
+ res = &dev->resource[pos];
+ res->name = dev->name;
+ reg = PCI_BASE_ADDRESS_0 + (pos << 2);
+ pci_read_config_dword(dev, reg, &l);
+ pci_write_config_dword(dev, reg, ~0);
+ pci_read_config_dword(dev, reg, &sz);
+ pci_write_config_dword(dev, reg, l);
+ if (!sz || sz == 0xffffffff)
+ continue;
+ if (l == 0xffffffff)
+ l = 0;
+ if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
+ res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
+ res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;
+ sz = pci_size(sz, PCI_BASE_ADDRESS_MEM_MASK);
+ } else {
+ res->start = l & PCI_BASE_ADDRESS_IO_MASK;
+ res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK;
+ sz = pci_size(sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff);
+ }
+ res->end = res->start + (unsigned long) sz;
+ res->flags |= pci_calc_resource_flags(l);
+ if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
+ == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
+ pci_read_config_dword(dev, reg+4, &l);
+ next++;
+#if BITS_PER_LONG == 64
+ res->start |= ((unsigned long) l) << 32;
+ res->end = res->start + sz;
+ pci_write_config_dword(dev, reg+4, ~0);
+ pci_read_config_dword(dev, reg+4, &sz);
+ pci_write_config_dword(dev, reg+4, l);
+ if (~sz)
+ res->end = res->start + 0xffffffff +
+ (((unsigned long) ~sz) << 32);
+#else
+ if (l) {
+ printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", dev->slot_name);
+ res->start = 0;
+ res->flags = 0;
+ continue;
+ }
+#endif
+ }
+ }
+ if (rom) {
+ dev->rom_base_reg = rom;
+ res = &dev->resource[PCI_ROM_RESOURCE];
+ pci_read_config_dword(dev, rom, &l);
+ pci_write_config_dword(dev, rom, ~PCI_ROM_ADDRESS_ENABLE);
+ pci_read_config_dword(dev, rom, &sz);
+ pci_write_config_dword(dev, rom, l);
+ if (l == 0xffffffff)
+ l = 0;
+ if (sz && sz != 0xffffffff) {
+ res->flags = (l & PCI_ROM_ADDRESS_ENABLE) |
+ IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
+ res->start = l & PCI_ROM_ADDRESS_MASK;
+ sz = pci_size(sz, PCI_ROM_ADDRESS_MASK);
+ res->end = res->start + (unsigned long) sz;
+ }
+ res->name = dev->name;
+ }
+}
+
+void __devinit pci_read_bridge_bases(struct pci_bus *child)
+{
+ struct pci_dev *dev = child->self;
+ u8 io_base_lo, io_limit_lo;
+ u16 mem_base_lo, mem_limit_lo;
+ unsigned long base, limit;
+ struct resource *res;
+ int i;
+
+ if (!dev) /* It's a host bus, nothing to read */
+ return;
+
+ for(i=0; i<3; i++)
+ child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
+
+ res = child->resource[0];
+ pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
+ pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
+ base = (io_base_lo & PCI_IO_RANGE_MASK) << 8;
+ limit = (io_limit_lo & PCI_IO_RANGE_MASK) << 8;
+
+ if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
+ u16 io_base_hi, io_limit_hi;
+ pci_read_config_word(dev, PCI_IO_BASE_UPPER16, &io_base_hi);
+ pci_read_config_word(dev, PCI_IO_LIMIT_UPPER16, &io_limit_hi);
+ base |= (io_base_hi << 16);
+ limit |= (io_limit_hi << 16);
+ }
+
+ if (base && base <= limit) {
+ res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
+ res->start = base;
+ res->end = limit + 0xfff;
+ res->name = child->name;
+ } else {
+ /*
+ * Ugh. We don't know enough about this bridge. Just assume
+ * that it's entirely transparent.
+ */
+ printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 0);
+ child->resource[0] = child->parent->resource[0];
+ }
+
+ res = child->resource[1];
+ pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
+ pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo);
+ base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
+ limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
+ if (base && base <= limit) {
+ res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
+ res->start = base;
+ res->end = limit + 0xfffff;
+ res->name = child->name;
+ } else {
+ /* See comment above. Same thing */
+ printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 1);
+ child->resource[1] = child->parent->resource[1];
+ }
+
+ res = child->resource[2];
+ pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
+ pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo);
+ base = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
+ limit = (mem_limit_lo & PCI_PREF_RANGE_MASK) << 16;
+
+ if ((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
+ u32 mem_base_hi, mem_limit_hi;
+ pci_read_config_dword(dev, PCI_PREF_BASE_UPPER32, &mem_base_hi);
+ pci_read_config_dword(dev, PCI_PREF_LIMIT_UPPER32, &mem_limit_hi);
+#if BITS_PER_LONG == 64
+ base |= ((long) mem_base_hi) << 32;
+ limit |= ((long) mem_limit_hi) << 32;
+#else
+ if (mem_base_hi || mem_limit_hi) {
+ printk(KERN_ERR "PCI: Unable to handle 64-bit address space for %s\n", child->name);
+ return;
+ }
+#endif
+ }
+ if (base && base <= limit) {
+ res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH;
+ res->start = base;
+ res->end = limit + 0xfffff;
+ res->name = child->name;
+ } else {
+ /* See comments above */
+ printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 2);
+ child->resource[2] = child->parent->resource[2];
+ }
+}
+
+static struct pci_bus * __devinit pci_alloc_bus(void)
+{
+ struct pci_bus *b;
+
+ b = kmalloc(sizeof(*b), GFP_KERNEL);
+ if (b) {
+ memset(b, 0, sizeof(*b));
+ INIT_LIST_HEAD(&b->children);
+ INIT_LIST_HEAD(&b->devices);
+ }
+ return b;
+}
+
+struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, 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;
+
+ /*
+ * 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.. */
+ for (i = 0; i < 4; i++)
+ child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
+
+ return child;
+}
+
+unsigned int __devinit pci_do_scan_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
+ * be handled by the bridge driver itself.
+ *
+ * We need to process bridges in two passes -- first we scan those
+ * already configured by the BIOS and after we are done with all of
+ * them, we proceed to assigning numbers to the remaining buses in
+ * order to avoid overlaps between old and new bus numbers.
+ */
+static int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass)
+{
+ unsigned int buses;
+ unsigned short cr;
+ struct pci_bus *child;
+ int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
+
+ pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
+ DBG("Scanning behind PCI bridge %s, config %06x, pass %d\n", dev->slot_name, buses & 0xffffff, pass);
+ if ((buses & 0xffff00) && !pcibios_assign_all_busses()) {
+ /*
+ * Bus already configured by firmware, process it in the first
+ * pass and just note the configuration.
+ */
+ if (pass)
+ return max;
+ child = pci_add_new_bus(bus, dev, 0);
+ child->primary = buses & 0xFF;
+ child->secondary = (buses >> 8) & 0xFF;
+ child->subordinate = (buses >> 16) & 0xFF;
+ child->number = child->secondary;
+ if (!is_cardbus) {
+ unsigned int cmax = pci_do_scan_bus(child);
+ if (cmax > max) max = cmax;
+ } else {
+ unsigned int cmax = child->subordinate;
+ if (cmax > max) max = cmax;
+ }
+ } else {
+ /*
+ * We need to assign a number to this bus which we always
+ * do in the second pass. We also keep all address decoders
+ * on the bridge disabled during scanning. FIXME: Why?
+ */
+ if (!pass)
+ return max;
+ pci_read_config_word(dev, PCI_COMMAND, &cr);
+ pci_write_config_word(dev, PCI_COMMAND, 0x0000);
+ pci_write_config_word(dev, PCI_STATUS, 0xffff);
+
+ child = pci_add_new_bus(bus, dev, ++max);
+ buses = (buses & 0xff000000)
+ | ((unsigned int)(child->primary) << 0)
+ | ((unsigned int)(child->secondary) << 8)
+ | ((unsigned int)(child->subordinate) << 16);
+ /*
+ * 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);
+ } else {
+ /*
+ * For CardBus bridges, we leave 4 bus numbers
+ * as cards with a PCI-to-PCI bridge can be
+ * inserted later.
+ */
+ max += 3;
+ }
+ /*
+ * Set the subordinate bus number to its real value.
+ */
+ child->subordinate = max;
+ pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
+ pci_write_config_word(dev, PCI_COMMAND, cr);
+ }
+ sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number);
+
+ return max;
+}
+
+/*
+ * Read interrupt line and base address registers.
+ * The architecture-dependent code can tweak these, of course.
+ */
+static void pci_read_irq(struct pci_dev *dev)
+{
+ unsigned char irq;
+
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq);
+ if (irq)
+ pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+ dev->irq = irq;
+}
+
+/**
+ * pci_setup_device - fill in class and map information of a device
+ * @dev: the device structure to fill
+ *
+ * Initialize the device structure with information about the device's
+ * vendor,class,memory and IO-space addresses,IRQ lines etc.
+ * Called at initialisation of the PCI subsystem and by CardBus services.
+ * Returns 0 on success and -1 if unknown type of device (not normal, bridge
+ * or CardBus).
+ */
+int pci_setup_device(struct pci_dev * dev)
+{
+ u32 class;
+
+ sprintf(dev->slot_name, "%02x:%02x.%d", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+ sprintf(dev->name, "PCI device %04x:%04x", dev->vendor, dev->device);
+
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
+ class >>= 8; /* upper 3 bytes */
+ 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);
+
+ /* "Unknown power state" */
+ dev->current_state = 4;
+
+ switch (dev->hdr_type) { /* header type */
+ case PCI_HEADER_TYPE_NORMAL: /* standard header */
+ if (class == PCI_CLASS_BRIDGE_PCI)
+ goto bad;
+ pci_read_irq(dev);
+ pci_read_bases(dev, 6, PCI_ROM_ADDRESS);
+ pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);
+ pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device);
+ break;
+
+ case PCI_HEADER_TYPE_BRIDGE: /* bridge header */
+ if (class != PCI_CLASS_BRIDGE_PCI)
+ goto bad;
+ pci_read_bases(dev, 2, PCI_ROM_ADDRESS1);
+ break;
+
+ case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */
+ if (class != PCI_CLASS_BRIDGE_CARDBUS)
+ goto bad;
+ pci_read_irq(dev);
+ pci_read_bases(dev, 1, 0);
+ pci_read_config_word(dev, PCI_CB_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);
+ pci_read_config_word(dev, PCI_CB_SUBSYSTEM_ID, &dev->subsystem_device);
+ break;
+
+ default: /* unknown header */
+ printk(KERN_ERR "PCI: device %s has unknown header type %02x, ignoring.\n",
+ dev->slot_name, dev->hdr_type);
+ return -1;
+
+ bad:
+ printk(KERN_ERR "PCI: %s: class %x doesn't match header type %02x. Ignoring class.\n",
+ dev->slot_name, class, dev->hdr_type);
+ dev->class = PCI_CLASS_NOT_DEFINED;
+ }
+
+ /* We found a fine healthy device, go go go... */
+ return 0;
+}
+
+/*
+ * 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)
+{
+ struct pci_dev *dev;
+ u32 l;
+
+ if (pci_read_config_dword(temp, 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);
+ if (!dev)
+ return NULL;
+
+ memcpy(dev, temp, sizeof(*dev));
+ dev->vendor = l & 0xffff;
+ dev->device = (l >> 16) & 0xffff;
+
+ /* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
+ set this higher, assuming the system even supports it. */
+ dev->dma_mask = 0xffffffff;
+ if (pci_setup_device(dev) < 0) {
+ kfree(dev);
+ return NULL;
+ }
+
+ /* now put in global tree */
+ strcpy(dev->dev.name,dev->name);
+ strcpy(dev->dev.bus_id,dev->slot_name);
+
+ device_register(&dev->dev);
+ return dev;
+}
+
+struct pci_dev * __devinit pci_scan_slot(struct pci_dev *temp)
+{
+ 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;
+
+ 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;
+
+ dev = pci_scan_device(temp);
+ if (!dev)
+ continue;
+ pci_name_device(dev);
+ if (!func) {
+ is_multi = hdr_type & 0x80;
+ first_dev = dev;
+ }
+
+ /*
+ * Link the device to both the global PCI device chain and
+ * the per-bus list of devices.
+ */
+ list_add_tail(&dev->global_list, &pci_devices);
+ list_add_tail(&dev->bus_list, &bus->devices);
+
+ /* Fix up broken headers */
+ pci_fixup_device(PCI_FIXUP_HEADER, dev);
+ }
+ return first_dev;
+}
+
+unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
+{
+ unsigned int devfn, max, pass;
+ struct list_head *ln;
+ struct pci_dev *dev, dev0;
+
+ DBG("Scanning bus %02x\n", bus->number);
+ max = bus->secondary;
+
+ /* Create a device template */
+ memset(&dev0, 0, sizeof(dev0));
+ dev0.bus = bus;
+ dev0.sysdata = bus->sysdata;
+ dev0.dev.parent = bus->dev;
+ dev0.dev.driver = &pci_device_driver;
+
+ /* Go find them, Rover! */
+ for (devfn = 0; devfn < 0x100; devfn += 8) {
+ dev0.devfn = devfn;
+ pci_scan_slot(&dev0);
+ }
+
+ /*
+ * 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);
+ 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)
+ max = pci_scan_bridge(bus, dev, max, pass);
+ }
+
+ /*
+ * 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("Bus scan for %02x returning with max=%02x\n", bus->number, max);
+ return max;
+}
+
+int __devinit pci_bus_exists(const struct list_head *list, int nr)
+{
+ const struct list_head *l;
+
+ for(l=list->next; l != list; l = l->next) {
+ const struct pci_bus *b = pci_bus_b(l);
+ if (b->number == nr || pci_bus_exists(&b->children, nr))
+ return 1;
+ }
+ return 0;
+}
+
+struct pci_bus * __devinit pci_alloc_primary_bus(int bus)
+{
+ struct pci_bus *b;
+
+ if (pci_bus_exists(&pci_root_buses, bus)) {
+ /* If we already got to this bus through a different bridge, ignore it */
+ DBG("PCI: Bus %02x already known\n", bus);
+ return NULL;
+ }
+
+ b = pci_alloc_bus();
+ if (!b)
+ return NULL;
+ list_add_tail(&b->node, &pci_root_buses);
+
+ b->dev = kmalloc(sizeof(*(b->dev)),GFP_KERNEL);
+ memset(b->dev,0,sizeof(*(b->dev)));
+ sprintf(b->dev->bus_id,"pci%d",bus);
+ strcpy(b->dev->name,"Host/PCI Bridge");
+ device_register(b->dev);
+
+ b->number = b->secondary = bus;
+ b->resource[0] = &ioport_resource;
+ b->resource[1] = &iomem_resource;
+ return b;
+}
+
+struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata)
+{
+ struct pci_bus *b = pci_alloc_primary_bus(bus);
+ if (b) {
+ b->sysdata = sysdata;
+ b->ops = ops;
+ b->subordinate = pci_do_scan_bus(b);
+ }
+ return b;
+}
+
+EXPORT_SYMBOL(pci_devices);
+EXPORT_SYMBOL(pci_root_buses);
+
+#ifdef CONFIG_HOTPLUG
+EXPORT_SYMBOL(pci_setup_device);
+EXPORT_SYMBOL(pci_add_new_bus);
+EXPORT_SYMBOL(pci_do_scan_bus);
+EXPORT_SYMBOL(pci_scan_slot);
+#endif
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index de6f42c53a40..aa3371c76d29 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -6,11 +6,9 @@
* Copyright (c) 1997--1999 Martin Mares <mj@ucw.cz>
*/
-#include <linux/types.h>
-#include <linux/kernel.h>
#include <linux/pci.h>
+#include <linux/module.h>
#include <linux/proc_fs.h>
-#include <linux/init.h>
#include <linux/seq_file.h>
#include <linux/smp_lock.h>
@@ -615,3 +613,11 @@ static int __init pci_proc_init(void)
}
__initcall(pci_proc_init);
+
+#ifdef CONFIG_HOTPLUG
+EXPORT_SYMBOL(pci_proc_attach_device);
+EXPORT_SYMBOL(pci_proc_detach_device);
+EXPORT_SYMBOL(pci_proc_attach_bus);
+EXPORT_SYMBOL(pci_proc_detach_bus);
+#endif
+
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
new file mode 100644
index 000000000000..5d88a020fb4a
--- /dev/null
+++ b/drivers/pci/search.c
@@ -0,0 +1,110 @@
+#include <linux/pci.h>
+#include <linux/module.h>
+
+/**
+ * pci_find_slot - locate PCI device from a given PCI slot
+ * @bus: number of PCI bus on which desired PCI device resides
+ * @devfn: encodes number of PCI slot in which the desired PCI
+ * device resides and the logical device number within that slot
+ * in case of multi-function devices.
+ *
+ * Given a PCI bus and slot/function number, the desired PCI device
+ * is located in system global list of PCI devices. If the device
+ * is found, a pointer to its data structure is returned. If no
+ * device is found, %NULL is returned.
+ */
+struct pci_dev *
+pci_find_slot(unsigned int bus, unsigned int devfn)
+{
+ struct pci_dev *dev;
+
+ pci_for_each_dev(dev) {
+ if (dev->bus->number == bus && dev->devfn == devfn)
+ return dev;
+ }
+ return NULL;
+}
+
+/**
+ * pci_find_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
+ * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
+ * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
+ * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids
+ * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
+ * @from: Previous PCI device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known PCI devices. If a PCI device is
+ * found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
+ * device structure is returned. Otherwise, %NULL is returned.
+ * A new search is initiated by passing %NULL to the @from argument.
+ * Otherwise if @from is not %NULL, searches continue from next device on the global list.
+ */
+struct pci_dev *
+pci_find_subsys(unsigned int vendor, unsigned int device,
+ unsigned int ss_vendor, unsigned int ss_device,
+ const struct pci_dev *from)
+{
+ struct list_head *n = from ? from->global_list.next : pci_devices.next;
+
+ while (n != &pci_devices) {
+ struct pci_dev *dev = pci_dev_g(n);
+ if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
+ (device == PCI_ANY_ID || dev->device == device) &&
+ (ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) &&
+ (ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device))
+ return dev;
+ n = n->next;
+ }
+ return NULL;
+}
+
+
+/**
+ * pci_find_device - begin or continue searching for a PCI device by vendor/device id
+ * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
+ * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
+ * @from: Previous PCI device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known PCI devices. If a PCI device is
+ * found with a matching @vendor and @device, a pointer to its device structure is
+ * returned. Otherwise, %NULL is returned.
+ * A new search is initiated by passing %NULL to the @from argument.
+ * Otherwise if @from is not %NULL, searches continue from next device on the global list.
+ */
+struct pci_dev *
+pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from)
+{
+ return pci_find_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
+}
+
+
+/**
+ * pci_find_class - begin or continue searching for a PCI device by class
+ * @class: search for a PCI device with this class designation
+ * @from: Previous PCI device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known PCI devices. If a PCI device is
+ * found with a matching @class, a pointer to its device structure is
+ * returned. Otherwise, %NULL is returned.
+ * A new search is initiated by passing %NULL to the @from argument.
+ * Otherwise if @from is not %NULL, searches continue from next device
+ * on the global list.
+ */
+struct pci_dev *
+pci_find_class(unsigned int class, const struct pci_dev *from)
+{
+ struct list_head *n = from ? from->global_list.next : pci_devices.next;
+
+ while (n != &pci_devices) {
+ struct pci_dev *dev = pci_dev_g(n);
+ if (dev->class == class)
+ return dev;
+ n = n->next;
+ }
+ return NULL;
+}
+
+EXPORT_SYMBOL(pci_find_class);
+EXPORT_SYMBOL(pci_find_device);
+EXPORT_SYMBOL(pci_find_slot);
+EXPORT_SYMBOL(pci_find_subsys);