From mboxrd@z Thu Jan 1 00:00:00 1970 From: John Carlson Date: Fri, 08 Feb 2002 15:44:14 +0000 Subject: Re: PCI hotplug question: resources Message-Id: List-Id: References: In-Reply-To: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: linux-hotplug@vger.kernel.org Here is the method used by the company I am employed by to rescan the PCI bus after the FPGA has been loaded (via ISA bus). The routine was a quick hack and therefor, is not complete. There is no module exit routine for cleanup, the routine cannot remove a device, and it will only look for a specific device. I have already shared this routine with Dirk Stieler who reports that it works for him. regards, John Carlson IFR Systems, Inc Wichita, KS <<---------------------CUT HERE------------------->> /* * rescan-pci.c: * * This program is now a standalone driver which will allow the user * to rescan the pci bus looking for new devices. This was necessary * because the core logic of the fpga has not been loaded during the * initial pci bus scan at startup. Once the kernel is initialized and * has downloaded the core logic to the fpga, the pci bus must be re-scanned * so that the boards pci interface can be registered with the kernel * and inserted into the pci_dev tree. * * The proper use of this driver is as follows: * * download the core logic into the fpga * issue 'modprobe pci-rescan' * * Copyright (C) 2000, Olivier Lebaillif, IFR Systems, Inc. * Copyright (C) 2001, John Carlson, IFR Systems, Inc. * * This program is a part of the Linux kernel, and may be freely * copied under the terms of the GNU General Public License (GPL), * version 2, or at your option any later version. * * $Log: rescan-pci.c,v $ * Revision 1.1 2001/10/31 17:16:28 jcarlson * Initial Version * */ /* * The standard includes */ #include #include #include #include #include #include #include #include #include #include #include /* * Including this file requires that this * routine must be built after the normal * pci routines. */ #include "../arch/i386/kernel/pci-i386.h" #define DEBUG static char version[] __devinitdata = "PCI Bus Rescanner: Version 1.1"; static char Copyright[] __devinitdata "Copyright (C) 2001, John Carlson, IFR Systems, Inc"; unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2; static int debug = -1; static int irq = 0; MODULE_AUTHOR ("John Carlson "); MODULE_DESCRIPTION ("Bus re-scan driver for PCI Bus"); MODULE_LICENSE("GPL"); MODULE_PARM (debug, "i"); MODULE_PARM (irq, "i"); struct pci_device_info { unsigned short device; unsigned short seen; const char *name; }; struct pci_vendor_info { unsigned short vendor; unsigned short nr; const char *name; struct pci_device_info *devices; }; /* * This is ridiculous, but we want the strings in * the .init section so that they don't take up * real memory.. Parse the same file multiple times * to get all the info. */ #define VENDOR( vendor, name ) static const char __vendorstr_##vendor[] __initdata = name; #define ENDVENDOR() #define DEVICE( vendor, device, name ) static const char __devicestr_##vendor##device[] __init data = name;#include "../drivers/pci/devlist.h" #define VENDOR( vendor, name ) static struct pci_device_info __devices_##vendor[] __initdata { #define ENDVENDOR() }; #define DEVICE( vendor, device, name ) { 0x##device, 0, __devicestr_##vendor##device }, #include "../drivers/pci/devlist.h" static const struct pci_vendor_info __initdata pci_vendor_list[] = { #define VENDOR( vendor, name ) { 0x##vendor, sizeof(__devices_##vendor) / sizeof(struct pci_de vice_info), __vendorstr_##vendor, __devices_##vendor }, #define ENDVENDOR() #define DEVICE( vendor, device, name ) #include "../drivers/pci/devlist.h" }; #define VENDORS (sizeof(pci_vendor_list)/sizeof(struct pci_vendor_info)) void __init pci_name_device (struct pci_dev *dev) { const struct pci_vendor_info *vendor_p pci_vendor_list; int i = VENDORS; char *name = dev->name; do { if (vendor_p->vendor = dev->vendor) goto match_vendor; vendor_p++; } while (--i); if (debug >= 2) printk (KERN_ERR "Vendor & Device not found for %04x:%04x\n", dev->vendor, dev->device); /* * Couldn't find either the vendor nor the device */ sprintf (name, "PCI device %04x:%04x", dev->vendor, dev->device); return; match_vendor: { struct pci_device_info *device_p vendor_p->devices; int i = vendor_p->nr; while (i > 0) { if (device_p->device = dev->device) goto match_device; device_p++; i--; } if (debug >= 2) printk (KERN_ERR "Vendor %s found for %04x:%04x\n", vendor_p->name, dev->vendor, dev->device); /* * Ok, found the vendor, but unknown device */ sprintf (name, "PCI device %04x:%04x (%s)", dev->vendor, dev->device, vendor_p->name); return; /* Full match */ match_device: { char *n = name + sprintf (name, "%s %s", vendor_p->name, device_p->name); int nr = device_p->seen + 1; if (debug >= 2) printk (KERN_ERR "Device Found %s\n", name); device_p->seen = nr; if (nr > 1) sprintf (n, " (#%d)", nr); } } } /* * This function detects the presence of the PCI core from XIlinx and * creates an entry in the PCI tree structure of the kernel. Initialization * of the config registers will be done as well as the allocation of an * IRQ line */int __init check_hw (void) { u8 b; u8 irq_pin; u32 l; int r; int devfn; struct pci_bus *bus; struct pci_dev dev0, *dev = NULL; /* a little announce */ DBG (KERN_INFO "rescan-pci.c: check_hw\n"); /* * get access to the bus 0. We are not looking on all the * other buses. The xilinx FPGA must be on bus 0 unless we * have to add a bridge in our design */ bus = pci_bus_b (pci_root_buses.next); if (debug >= 3) printk (KERN_ERR "Bus = %x\n", bus->number); /* Create a device template */ memset (&dev0, 0, sizeof (dev0)); dev0.bus = bus; dev0.sysdata = bus->sysdata; /* * Go find all devices function 0, we don't look * at the functions 1 to 7 */ devfn = 0; while ((devfn < 0x100) && (!dev)) { dev0.devfn = devfn; /* * read the PCI device header and store it * (masking the multi-function bit) */ pci_read_config_byte (&dev0, PCI_HEADER_TYPE, &b); dev0.hdr_type = b & 0x7f; /* read the vendor and device Ids */ pci_read_config_dword (&dev0, PCI_VENDOR_ID, &l); if (l = PCI_ID_CAI) { /* * we found our board. Let's make sure it has * the proper header, if not return no device found */ if (b !PCI_HEADER_TYPE_NORMAL) return -ENODEV; /* we now have to configure and register it */ /* first allocate memory for the device */ dev = kmalloc (sizeof (*dev), GFP_KERNEL); if (!dev) return -ENOMEM; /* copy the data existing in the temporary device */ memcpy (dev, &dev0, sizeof (*dev)); /* set the vendo id and device id */ dev->vendor = l & 0xffff; dev->device = (l >> 16) & 0xffff; dev->bus = bus; dev->sysdata = bus->sysdata; dev->devfn = devfn; dev->hdr_type = b & 0x7f; /* Does this function have an interrupt at all? */ pci_read_config_byte (dev, PCI_INTERRUPT_PIN, &irq_pin); if (irq_pin) { dev->irq = irq; pci_write_config_byte (dev, PCI_INTERRUPT_LINE, irq); } if (pci_setup_device (dev)) { kfree (dev); printk (KERN_ERR "Could not setup device\n"); return -ENODEV; } /* * Go let the kernel allocate * the requested resources */ for (r = 0; r < 7; r++) { struct resource *res dev->resource + r; if (res->flags) pci_assign_resource (dev, r); } if (pci_enable_device (dev)) { kfree (dev); printk (KERN_ERR "Could not enable device\n"); return -ENODEV; } /* try to get the name of the actual device */ pci_name_device (dev); /* get the revision information */ pci_read_config_dword (dev, PCI_CLASS_REVISION, &l); dev->class = l >> 8; /* read the subsystem id and subsystem vendor id */ pci_read_config_word (dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor); pci_read_config_word (dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device); /* * Link the device to both the global PCI device * chain and the per-bus list of devices. */ pci_insert_device (dev, bus); if (debug >= 1) printk (KERN_ERR "Xilinx device linked to PCI device chain\n"); /* we are all set return 0 */ return 0; } /* go check the next device */ devfn += 8; } /* if we reach this point the device has not been found */ return -ENODEV; } /* Initialization entry point for the module */ int __init pci_cai_init_module (void) { struct pci_dev *dev = NULL; unsigned long flags; int ret; printk (KERN_ERR "\n%s\n%s\n", version, Copyright); __save_flags (flags); __cli (); dev = pci_find_device (PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_CAI, dev); if (!dev) { /* initialize our hardware */ if ((ret = check_hw ()) < 0) { __restore_flags (flags); if (debug >= 2) printk (KERN_ERR "check_hw returned error %x\n", ret); printk (KERN_ERR "Cannot initialize the Xilinx HW, pci device not installed."); return -ENODEV; } } __restore_flags (flags); return 0; } module_init (pci_cai_init_module); <<-----------------END----------------->> __________________________________________________ Do You Yahoo!? Send FREE Valentine eCards with Yahoo! Greetings! http://greetings.yahoo.com _______________________________________________ Linux-hotplug-devel mailing list http://linux-hotplug.sourceforge.net Linux-hotplug-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel