lkml.org 
[lkml]   [1999]   [Sep]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRFC: PCI probing
Attached is a patch against 2.3.18ac3, which adds simple PCI probing,
and demonstrates the usage of it in drivers/block/cpqarray.c, which
shrinks quite a bit. Comments welcome.

Jeff



--
Custom driver development | Never worry about theory as long
Open source programming | as the machinery does what it's
| supposed to do. -- R. A. Heinleindiff -urN linux.ac3/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c
--- linux.ac3/drivers/block/cpqarray.c Wed Sep 8 14:51:22 1999
+++ linux/drivers/block/cpqarray.c Wed Sep 15 02:22:40 1999
@@ -87,6 +87,16 @@
{ 0x40510E11, "Smart Array 4250ES", &smart4_access },
};

+static struct pci_simple_probe_entry cpqarray_pci_table[] __initdata = {
+ { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_COMPAQ_42XX,
+ 0, 0, NULL },
+ { PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C1510,
+ PCI_VENDOR_ID_COMPAQ, 0, NULL },
+ { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_SMART2P,
+ 0, 0, NULL },
+ { 0, 0, } /* terminate table */
+};
+
static struct hd_struct * ida;
static int * ida_sizes;
static int * ida_blocksizes;
@@ -105,8 +115,9 @@
#define DBGPX(s) do { } while(0)

void cpqarray_init(void);
-static int cpqarray_pci_detect(void);
-static int cpqarray_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn);
+static int cpqarray_pci_probe_cb (struct pci_dev *dev, int match_num,
+ void *dev_data, void *drvr_data);
+static int cpqarray_pci_init(ctlr_info_t *c, struct pci_dev *pdev);
static ulong remap_pci_mem(ulong base, ulong size);
static int cpqarray_eisa_detect(void);
static int pollcomplete(int ctlr);
@@ -381,7 +392,7 @@
int i;

/* detect controllers */
- cpqarray_pci_detect();
+ pci_simple_probe (cpqarray_pci_table, 9, cpqarray_pci_probe_cb, NULL);
cpqarray_eisa_detect();

if (nr_ctlr == 0)
@@ -504,128 +515,54 @@
}

/*
- * Find the controller and initialize it
- * Cannot use the class code to search, because older array controllers use
- * 0x018000 and new ones use 0x010400. So I might as well search for each
- * each device IDs, being there are only going to be three of them.
+ * Receive a callback from the PCI probe helper. Allocate the
+ * structure necessary to hold controller info, then pass
+ * control to cpqarray_pci_init().
*/
-static int cpqarray_pci_detect(void)
+static int cpqarray_pci_probe_cb (struct pci_dev *dev, int match_num,
+ void *dev_data, void *drvr_data)
{
- int index;
- unchar bus=0, dev_fn=0;
+ int rc;

- /* This seems dumb, surely we could use an array of types to match ?? */
-
- for(index=0; ; index++) {
- if (pcibios_find_device(PCI_VENDOR_ID_DEC,
- PCI_DEVICE_ID_COMPAQ_42XX, index, &bus, &dev_fn))
- break;
- printk(KERN_DEBUG "42XX Device has been found at %x %x\n",
- bus, dev_fn);
- if (index == 1000000) break;
- if (nr_ctlr == 8) {
- printk("This driver supports a maximum of "
+ if (match_num > 8) {
+ printk(KERN_ERR "cpqarray: This driver supports a maximum of "
"8 controllers.\n");
- break;
- }
-
- hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
- if(hba[nr_ctlr]==NULL)
- {
- printk(KERN_ERR "cpqarray: out of memory.\n");
- continue;
- }
- memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
- if (cpqarray_pci_init(hba[nr_ctlr], bus, dev_fn) != 0)
- continue;
- sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr);
- hba[nr_ctlr]->ctlr = nr_ctlr;
- nr_ctlr++;
+ return 0;
}
-
- for(index=0; ; index++) {
- unsigned short subvendor=0;
-
- if (pcibios_find_device(PCI_VENDOR_ID_NCR,
- PCI_DEVICE_ID_NCR_53C1510, index, &bus, &dev_fn))
- break;
- printk(KERN_DEBUG "Integrated RAID Chip has been found at %x %x\n",
- bus, dev_fn);
- if(pcibios_read_config_word(bus, dev_fn,
- PCI_SUBSYSTEM_VENDOR_ID, &subvendor))
- {
- printk(KERN_DEBUG "cpqarray failed to read subvendor\n");
- break;
- }
- if(subvendor != PCI_VENDOR_ID_COMPAQ)
- break;
- printk(KERN_DEBUG "Its a compaq RAID Chip\n");
- if (index == 1000000) break;
- if (nr_ctlr == 8) {
- printk("This driver supports a maximum of "
- "8 controllers.\n");
- break;
- }
-
- hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
- if(hba[nr_ctlr]==NULL)
- {
- printk(KERN_ERR "cpqarray: out of memory.\n");
- continue;
- }
- memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
- /* DOESNT THIS LEAK MEMORY ?????? - AC */
- if (cpqarray_pci_init(hba[nr_ctlr], bus, dev_fn) != 0)
- continue;
- sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr);
- hba[nr_ctlr]->ctlr = nr_ctlr;
- nr_ctlr++;
- }
-
- for(index=0; ; index++) {
- if (pcibios_find_device(PCI_VENDOR_ID_COMPAQ,
- PCI_DEVICE_ID_COMPAQ_SMART2P, index, &bus, &dev_fn))
- break;
-
- if (index == 1000000) break;
- if (nr_ctlr == 8) {
- printk("This driver supports a maximum of "
- "8 controllers.\n");
- break;
- }
-
- hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
- if(hba[nr_ctlr]==NULL)
- {
- printk(KERN_ERR "cpqarray: out of memory.\n");
- continue;
- }
- memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
- if (cpqarray_pci_init(hba[nr_ctlr], bus, dev_fn) != 0)
- continue;
- sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr);
- hba[nr_ctlr]->ctlr = nr_ctlr;
- nr_ctlr++;
+ hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
+ if(hba[nr_ctlr]==NULL)
+ {
+ printk(KERN_ERR "cpqarray: out of memory.\n");
+ return -ENOMEM;
}
+ memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));

- return nr_ctlr;
+ /* DOESNT THIS LEAK MEMORY ?????? - AC */
+ rc = cpqarray_pci_init(hba[nr_ctlr], dev);
+ if (rc != 0)
+ return rc;
+
+ sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr);
+ hba[nr_ctlr]->ctlr = nr_ctlr;
+ nr_ctlr++;
+
+ return 0;
}
+
/*
* Find the IO address of the controller, its IRQ and so forth. Fill
* in some basic stuff into the ctlr_info_t structure.
*/
-static int cpqarray_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn)
+static int cpqarray_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
{
ushort vendor_id, device_id, command;
unchar cache_line_size, latency_timer;
unchar irq, revision;
uint addr[6];
__u32 board_id;
- struct pci_dev *pdev;

int i;

- pdev = pci_find_slot(bus, device_fn);
vendor_id = pdev->vendor;
device_id = pdev->device;
irq = pdev->irq;
@@ -633,16 +570,12 @@
for(i=0; i<6; i++)
addr[i] = pdev->resource[i].flags;

- (void) pcibios_read_config_word(bus, device_fn,
- PCI_COMMAND,&command);
- (void) pcibios_read_config_byte(bus, device_fn,
- PCI_CLASS_REVISION,&revision);
- (void) pcibios_read_config_byte(bus, device_fn,
- PCI_CACHE_LINE_SIZE, &cache_line_size);
- (void) pcibios_read_config_byte(bus, device_fn,
- PCI_LATENCY_TIMER, &latency_timer);
+ (void) pci_read_config_word(pdev,PCI_COMMAND,&command);
+ (void) pci_read_config_byte(pdev,PCI_CLASS_REVISION,&revision);
+ (void) pci_read_config_byte(pdev,PCI_CACHE_LINE_SIZE, &cache_line_size);
+ (void) pci_read_config_byte(pdev,PCI_LATENCY_TIMER, &latency_timer);

- (void) pcibios_read_config_dword(bus, device_fn, 0x2c, &board_id);
+ (void) pci_read_config_dword(pdev, 0x2c, &board_id);

DBGINFO(
printk("vendor_id = %x\n", vendor_id);
diff -urN linux.ac3/drivers/pci/Makefile linux/drivers/pci/Makefile
--- linux.ac3/drivers/pci/Makefile Wed Sep 1 17:37:25 1999
+++ linux/drivers/pci/Makefile Wed Sep 15 02:18:12 1999
@@ -25,6 +25,6 @@
L_OBJS += proc.o
endif

-L_OBJS += compat.o quirks.o names.o syscall.o setup.o
+L_OBJS += compat.o quirks.o names.o syscall.o setup.o helper.o

include $(TOPDIR)/Rules.make
diff -urN linux.ac3/drivers/pci/helper.c linux/drivers/pci/helper.c
--- linux.ac3/drivers/pci/helper.c Wed Dec 31 19:00:00 1969
+++ linux/drivers/pci/helper.c Wed Sep 15 02:17:39 1999
@@ -0,0 +1,55 @@
+/*
+ * $Id$
+ *
+ * PCI helpers, see include/linux/pci.h for further explanation.
+ *
+ * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+
+int pci_simple_probe (struct pci_simple_probe_entry *list, size_t match_limit,
+ pci_simple_probe_callback cb, void *drvr_data)
+{
+ struct pci_dev *dev;
+ struct pci_simple_probe_entry *ent;
+ size_t matches = 0;
+ unsigned short vendor, device;
+ int rc;
+
+ if (!list || !cb)
+ return -1;
+
+ ent = list;
+ vendor = ent->vendor;
+ device = ent->device;
+ while (vendor && device) {
+ dev = pci_find_device (vendor, device, NULL);
+ for (; dev; dev = pci_find_device (vendor, device, dev)) {
+
+ if (((ent->subsys_vendor) &&
+ (ent->subsys_vendor != dev->subsystem_vendor)) ||
+ ((ent->subsys_device) &&
+ (ent->subsys_device != dev->subsystem_device)))
+ continue;
+
+ rc = (* cb) (dev, matches, ent->dev_data, drvr_data);
+ if (rc < 0)
+ return rc;
+
+ matches++;
+
+ if (match_limit && match_limit == matches)
+ return matches;
+ }
+
+ ent++;
+ vendor = ent->vendor;
+ device = ent->device;
+ }
+
+ return matches;
+}
diff -urN linux.ac3/include/linux/pci.h linux/include/linux/pci.h
--- linux.ac3/include/linux/pci.h Wed Sep 15 01:00:42 1999
+++ linux/include/linux/pci.h Wed Sep 15 02:15:35 1999
@@ -1598,5 +1598,25 @@

void pci_fixup_device(int pass, struct pci_dev *dev);

+
+/*
+ * simple PCI probing for drivers
+ */
+
+typedef int (*pci_simple_probe_callback) (struct pci_dev *dev, int match_num,
+ void *dev_data, void *drvr_data);
+
+struct pci_simple_probe_entry {
+ unsigned short vendor; /* vendor id, PCI_ANY_ID, or 0 for last entry */
+ unsigned short device; /* device id, PCI_ANY_ID, or 0 for last entry */
+ unsigned short subsys_vendor; /* subsystem vendor id, 0 for don't care */
+ unsigned short subsys_device; /* subsystem device id, 0 for don't care */
+ void *dev_data; /* driver-private, entry-specific data */
+};
+
+int pci_simple_probe (struct pci_simple_probe_entry *list, size_t match_limit,
+ pci_simple_probe_callback cb, void *drvr_data);
+
+
#endif /* __KERNEL__ */
#endif /* LINUX_PCI_H */
\
 
 \ /
  Last update: 2005-03-22 13:54    [W:0.081 / U:1.004 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site