bk://kernel.bkbits.net/gregkh/linux/pci-2.6 johnrose@austin.ibm.com|ChangeSet|20050113234059|51355 johnrose # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2005/01/13 15:40:59-08:00 johnrose@austin.ibm.com # [PATCH] PCI: fix release_pcibus_dev() crash # # During the course of a hotplug removal of a PCI bus, release_pcibus_dev() # attempts to remove attribute files from a kobject directory that no longer # exists. This patch moves these calls to pci_remove_bus(), where they can work # as intended. # # Signed-off-by: John Rose # Signed-off-by: Greg Kroah-Hartman # # drivers/pci/remove.c # 2005/01/13 12:49:21-08:00 johnrose@austin.ibm.com +8 -5 # PCI: fix release_pcibus_dev() crash # # drivers/pci/probe.c # 2005/01/13 13:09:28-08:00 johnrose@austin.ibm.com +3 -7 # PCI: fix release_pcibus_dev() crash # # drivers/pci/pci.h # 2005/01/13 12:50:06-08:00 johnrose@austin.ibm.com +2 -0 # PCI: fix release_pcibus_dev() crash # # ChangeSet # 2005/01/12 19:01:29-08:00 tglx@linutronix.de # [PATCH] PCI: Lock initializer cleanup - batch 4 # # Use the new lock initializers DEFINE_SPIN_LOCK and DEFINE_RW_LOCK # # Signed-off-by: Thomas Gleixner # Signed-off-by: Greg Kroah-Hartman # # drivers/pci/search.c # 2005/01/12 13:59:26-08:00 tglx@linutronix.de +1 -1 # PCI: Lock initializer cleanup - batch 4 # # drivers/pci/msi.c # 2005/01/12 13:59:27-08:00 tglx@linutronix.de +1 -1 # PCI: Lock initializer cleanup - batch 4 # # drivers/pci/access.c # 2005/01/12 13:59:26-08:00 tglx@linutronix.de +1 -1 # PCI: Lock initializer cleanup - batch 4 # # ChangeSet # 2005/01/12 19:01:14-08:00 dhowells@redhat.com # [PATCH] PCI: Downgrade printk that complains about unsupported PCI PM caps # # The attached patch downgrades to KERN_DEBUG level the printk that issues a # notification that an unsupported version of the PCI power management registers # has been encountered by pci_set_power_state(). # # Signed-Off-By: David Howells # Signed-off-by: Greg Kroah-Hartman # # drivers/pci/pci.c # 2005/01/12 11:12:44-08:00 dhowells@redhat.com +1 -1 # PCI: Downgrade printk that complains about unsupported PCI PM caps # # ChangeSet # 2005/01/12 12:45:41-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-pci # # include/linux/pci_ids.h # 2005/01/12 12:45:37-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2005/01/11 22:01:17-08:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/pci-2.6 # into bix.(none):/usr/src/bk-pci # # arch/i386/Kconfig # 2005/01/11 22:01:12-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2005/01/11 16:05:33-08:00 jbarnes@sgi.com # [PATCH] PCI: rom.c cleanups # # Greg, here's some whitespace and long line cleanup I wanted to do last time I # touched rom.c, but forgot. Does it look ok to you, Jon? # # Signed-off-by: Jesse Barnes # Signed-off-by: Greg Kroah-Hartman # # drivers/pci/rom.c # 2005/01/09 15:26:30-08:00 jbarnes@sgi.com +41 -39 # PCI: rom.c cleanups # # ChangeSet # 2005/01/11 16:05:01-08:00 roland@topspin.com # [PATCH] PCI: Clean up printks in msi.c # # Add "PCI:" prefixes and fix up the formatting and grammar of printks # in drivers/pci/msi.c. The main motivation was to fix the shouting # "MSI INIT SUCCESS" message printed when an MSI-using driver is first # started, but while we're at it we might as well tidy up all the messages. # # Signed-off-by: Roland Dreier # Signed-off-by: Greg Kroah-Hartman # # drivers/pci/msi.c # 2005/01/10 09:37:38-08:00 roland@topspin.com +20 -17 # PCI: Clean up printks in msi.c # # ChangeSet # 2005/01/11 16:04:32-08:00 jason.d.gaston@intel.com # [PATCH] PCI: pci_ids.h correction for Intel ICH7 - 2.6.10-bk13 # # This patch corrects the ICH7 LPC controller DID in pci_ids.h from x27B0 # to x27B8. This patch was build against 2.6.10-bk13. # # Signed-off-by: Jason Gaston # Signed-off-by: Greg Kroah-Hartman # # include/linux/pci_ids.h # 2005/01/10 06:21:18-08:00 jason.d.gaston@intel.com +1 -1 # PCI: pci_ids.h correction for Intel ICH7 - 2.6.10-bk13 # # ChangeSet # 2005/01/11 16:04:00-08:00 bjorn.helgaas@hp.com # [PATCH] PCI: use modern format for PCI addresses # # Use pci_name() rather than "%02x:%02x" when printing PCI # address information. # # Signed-off-by: Bjorn Helgaas # Signed-off-by: Greg Kroah-Hartman # # arch/i386/pci/pcbios.c # 2005/01/11 08:41:24-08:00 bjorn.helgaas@hp.com +2 -2 # PCI: use modern format for PCI addresses # # ChangeSet # 2005/01/11 15:39:19-08:00 tlnguyen@snoqualmie.dp.intel.com # [PATCH] PCI: add PCI Express Port Bus Driver subsystem # # Signed-off-by: T. Long Nguyen # Signed-off-by: Greg Kroah-Hartman # # include/linux/pcieport_if.h # 2004/12/10 11:06:05-08:00 tlnguyen@snoqualmie.dp.intel.com +74 -0 # PCI: add PCI Express Port Bus Driver subsystem # # drivers/pci/pcie/portdrv_pci.c # 2004/12/10 12:31:35-08:00 tlnguyen@snoqualmie.dp.intel.com +138 -0 # PCI: add PCI Express Port Bus Driver subsystem # # drivers/pci/pcie/portdrv_core.c # 2004/12/10 12:32:48-08:00 tlnguyen@snoqualmie.dp.intel.com +453 -0 # PCI: add PCI Express Port Bus Driver subsystem # # drivers/pci/pcie/portdrv_bus.c # 2004/12/20 10:28:05-08:00 tlnguyen@snoqualmie.dp.intel.com +88 -0 # PCI: add PCI Express Port Bus Driver subsystem # # drivers/pci/pcie/portdrv.h # 2004/12/10 12:17:31-08:00 tlnguyen@snoqualmie.dp.intel.com +42 -0 # PCI: add PCI Express Port Bus Driver subsystem # # drivers/pci/pcie/Makefile # 2004/12/10 11:06:05-08:00 tlnguyen@snoqualmie.dp.intel.com +7 -0 # PCI: add PCI Express Port Bus Driver subsystem # # drivers/pci/pcie/Kconfig # 2004/12/20 10:26:20-08:00 tlnguyen@snoqualmie.dp.intel.com +38 -0 # PCI: add PCI Express Port Bus Driver subsystem # # include/linux/pcieport_if.h # 2004/12/10 11:06:05-08:00 tlnguyen@snoqualmie.dp.intel.com +0 -0 # BitKeeper file /home/greg/linux/BK/pci-2.6/include/linux/pcieport_if.h # # drivers/pci/pcie/portdrv_pci.c # 2004/12/10 12:31:35-08:00 tlnguyen@snoqualmie.dp.intel.com +0 -0 # BitKeeper file /home/greg/linux/BK/pci-2.6/drivers/pci/pcie/portdrv_pci.c # # drivers/pci/pcie/portdrv_core.c # 2004/12/10 12:32:48-08:00 tlnguyen@snoqualmie.dp.intel.com +0 -0 # BitKeeper file /home/greg/linux/BK/pci-2.6/drivers/pci/pcie/portdrv_core.c # # drivers/pci/pcie/portdrv_bus.c # 2004/12/20 10:28:05-08:00 tlnguyen@snoqualmie.dp.intel.com +0 -0 # BitKeeper file /home/greg/linux/BK/pci-2.6/drivers/pci/pcie/portdrv_bus.c # # drivers/pci/pcie/portdrv.h # 2004/12/10 12:17:31-08:00 tlnguyen@snoqualmie.dp.intel.com +0 -0 # BitKeeper file /home/greg/linux/BK/pci-2.6/drivers/pci/pcie/portdrv.h # # drivers/pci/pcie/Makefile # 2004/12/10 11:06:05-08:00 tlnguyen@snoqualmie.dp.intel.com +0 -0 # BitKeeper file /home/greg/linux/BK/pci-2.6/drivers/pci/pcie/Makefile # # drivers/pci/pcie/Kconfig # 2004/12/20 10:26:20-08:00 tlnguyen@snoqualmie.dp.intel.com +0 -0 # BitKeeper file /home/greg/linux/BK/pci-2.6/drivers/pci/pcie/Kconfig # # drivers/pci/hotplug/pciehp_hpc.c # 2004/12/10 11:06:05-08:00 tlnguyen@snoqualmie.dp.intel.com +6 -15 # PCI: add PCI Express Port Bus Driver subsystem # # drivers/pci/hotplug/pciehp_core.c # 2004/12/10 11:06:05-08:00 tlnguyen@snoqualmie.dp.intel.com +55 -28 # PCI: add PCI Express Port Bus Driver subsystem # # drivers/pci/hotplug/pciehp.h # 2004/12/10 11:06:05-08:00 tlnguyen@snoqualmie.dp.intel.com +2 -1 # PCI: add PCI Express Port Bus Driver subsystem # # drivers/pci/hotplug/Kconfig # 2004/12/10 11:06:05-08:00 tlnguyen@snoqualmie.dp.intel.com +0 -21 # PCI: add PCI Express Port Bus Driver subsystem # # drivers/Makefile # 2004/12/22 11:40:36-08:00 tlnguyen@snoqualmie.dp.intel.com +1 -0 # PCI: add PCI Express Port Bus Driver subsystem # # arch/i386/Kconfig # 2004/12/22 11:41:51-08:00 tlnguyen@snoqualmie.dp.intel.com +2 -0 # PCI: add PCI Express Port Bus Driver subsystem # # Documentation/PCIEBUS-HOWTO.txt # 2004/12/10 11:06:05-08:00 tlnguyen@snoqualmie.dp.intel.com +217 -0 # PCI: add PCI Express Port Bus Driver subsystem # # Documentation/PCIEBUS-HOWTO.txt # 2004/12/10 11:06:05-08:00 tlnguyen@snoqualmie.dp.intel.com +0 -0 # BitKeeper file /home/greg/linux/BK/pci-2.6/Documentation/PCIEBUS-HOWTO.txt # # ChangeSet # 2005/01/11 11:50:51-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-pci # # drivers/net/3c59x.c # 2005/01/11 11:50:46-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/i386/pci/irq.c # 2005/01/11 11:50:46-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2005/01/10 14:37:44-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-pci # # drivers/pci/quirks.c # 2005/01/10 14:37:40-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/via-velocity.c # 2005/01/10 14:37:40-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/via-rhine.c # 2005/01/10 14:37:40-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/typhoon.c # 2005/01/10 14:37:40-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/starfire.c # 2005/01/10 14:37:40-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/sis900.c # 2005/01/10 14:37:40-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/eepro100.c # 2005/01/10 14:37:40-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/e100.c # 2005/01/10 14:37:39-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/amd8111e.c # 2005/01/10 14:37:39-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/8139too.c # 2005/01/10 14:37:39-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/8139cp.c # 2005/01/10 14:37:39-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/3c59x.c # 2005/01/10 14:37:39-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/media/video/bttv-driver.c # 2005/01/10 14:37:39-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/i386/pci/irq.c # 2005/01/10 14:37:39-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2005/01/08 21:16:16-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-pci # # drivers/pci/quirks.c # 2005/01/08 21:16:11-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/via-velocity.c # 2005/01/08 21:16:11-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/via-rhine.c # 2005/01/08 21:16:11-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/starfire.c # 2005/01/08 21:16:11-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/eepro100.c # 2005/01/08 21:16:11-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/e100.c # 2005/01/08 21:16:11-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/amd8111e.c # 2005/01/08 21:16:11-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/8139cp.c # 2005/01/08 21:16:11-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/3c59x.c # 2005/01/08 21:16:11-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/media/video/bttv-driver.c # 2005/01/08 21:16:11-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2005/01/07 14:31:58-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-pci # # drivers/pci/quirks.c # 2005/01/07 14:31:54-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2005/01/06 19:37:00-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-pci # # drivers/net/eepro100.c # 2005/01/06 19:36:55-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/12/30 23:06:15-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-pci # # arch/i386/pci/irq.c # 2004/12/30 23:06:11-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/12/29 18:01:53-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-pci # # drivers/pci/quirks.c # 2004/12/29 18:01:48-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/typhoon.c # 2004/12/29 18:01:48-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/starfire.c # 2004/12/29 18:01:48-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/sis900.c # 2004/12/29 18:01:48-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/e100.c # 2004/12/29 18:01:48-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/8139too.c # 2004/12/29 18:01:48-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/net/3c59x.c # 2004/12/29 18:01:48-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/i386/pci/irq.c # 2004/12/29 18:01:48-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/12/27 00:21:57-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-pci # # drivers/net/via-rhine.c # 2004/12/27 00:21:53-08:00 akpm@bix.(none) +0 -0 # Auto merged # diff -Nru a/Documentation/PCIEBUS-HOWTO.txt b/Documentation/PCIEBUS-HOWTO.txt --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/Documentation/PCIEBUS-HOWTO.txt 2005-01-13 16:56:29 -08:00 @@ -0,0 +1,217 @@ + The PCI Express Port Bus Driver Guide HOWTO + Tom L Nguyen tom.l.nguyen@intel.com + 11/03/2004 + +1. About this guide + +This guide describes the basics of the PCI Express Port Bus driver +and provides information on how to enable the service drivers to +register/unregister with the PCI Express Port Bus Driver. + +2. Copyright 2004 Intel Corporation + +3. What is the PCI Express Port Bus Driver + +A PCI Express Port is a logical PCI-PCI Bridge structure. There +are two types of PCI Express Port: the Root Port and the Switch +Port. The Root Port originates a PCI Express link from a PCI Express +Root Complex and the Switch Port connects PCI Express links to +internal logical PCI buses. The Switch Port, which has its secondary +bus representing the switch's internal routing logic, is called the +switch's Upstream Port. The switch's Downstream Port is bridging from +switch's internal routing bus to a bus representing the downstream +PCI Express link from the PCI Express Switch. + +A PCI Express Port can provide up to four distinct functions, +referred to in this document as services, depending on its port type. +PCI Express Port's services include native hotplug support (HP), +power management event support (PME), advanced error reporting +support (AER), and virtual channel support (VC). These services may +be handled by a single complex driver or be individually distributed +and handled by corresponding service drivers. + +4. Why use the PCI Express Port Bus Driver? + +In existing Linux kernels, the Linux Device Driver Model allows a +physical device to be handled by only a single driver. The PCI +Express Port is a PCI-PCI Bridge device with multiple distinct +services. To maintain a clean and simple solution each service +may have its own software service driver. In this case several +service drivers will compete for a single PCI-PCI Bridge device. +For example, if the PCI Express Root Port native hotplug service +driver is loaded first, it claims a PCI-PCI Bridge Root Port. The +kernel therefore does not load other service drivers for that Root +Port. In other words, it is impossible to have multiple service +drivers load and run on a PCI-PCI Bridge device simultaneously +using the current driver model. + +To enable multiple service drivers running simultaneously requires +having a PCI Express Port Bus driver, which manages all populated +PCI Express Ports and distributes all provided service requests +to the corresponding service drivers as required. Some key +advantages of using the PCI Express Port Bus driver are listed below: + + - Allow multiple service drivers to run simultaneously on + a PCI-PCI Bridge Port device. + + - Allow service drivers implemented in an independent + staged approach. + + - Allow one service driver to run on multiple PCI-PCI Bridge + Port devices. + + - Manage and distribute resources of a PCI-PCI Bridge Port + device to requested service drivers. + +5. Configuring the PCI Express Port Bus Driver vs. Service Drivers + +5.1 Including the PCI Express Port Bus Driver Support into the Kernel + +Including the PCI Express Port Bus driver depends on whether the PCI +Express support is included in the kernel config. The kernel will +automatically include the PCI Express Port Bus driver as a kernel +driver when the PCI Express support is enabled in the kernel. + +5.2 Enabling Service Driver Support + +PCI device drivers are implemented based on Linux Device Driver Model. +All service drivers are PCI device drivers. As discussed above, it is +impossible to load any service driver once the kernel has loaded the +PCI Express Port Bus Driver. To meet the PCI Express Port Bus Driver +Model requires some minimal changes on existing service drivers that +imposes no impact on the functionality of existing service drivers. + +A service driver is required to use the two APIs shown below to +register its service with the PCI Express Port Bus driver (see +section 5.2.1 & 5.2.2). It is important that a service driver +initializes the pcie_port_service_driver data structure, included in +header file /include/linux/pcieport_if.h, before calling these APIs. +Failure to do so will result an identity mismatch, which prevents +the PCI Express Port Bus driver from loading a service driver. + +5.2.1 pcie_port_service_register + +int pcie_port_service_register(struct pcie_port_service_driver *new) + +This API replaces the Linux Driver Model's pci_module_init API. A +service driver should always calls pcie_port_service_register at +module init. Note that after service driver being loaded, calls +such as pci_enable_device(dev) and pci_set_master(dev) are no longer +necessary since these calls are executed by the PCI Port Bus driver. + +5.2.2 pcie_port_service_unregister + +void pcie_port_service_unregister(struct pcie_port_service_driver *new) + +pcie_port_service_unregister replaces the Linux Driver Model's +pci_unregister_driver. It's always called by service driver when a +module exits. + +5.2.3 Sample Code + +Below is sample service driver code to initialize the port service +driver data structure. + +static struct pcie_port_service_id service_id[] = { { + .vendor = PCI_ANY_ID, + .device = PCI_ANY_ID, + .port_type = PCIE_RC_PORT, + .service_type = PCIE_PORT_SERVICE_AER, + }, { /* end: all zeroes */ } +}; + +static struct pcie_port_service_driver root_aerdrv = { + .name = (char *)device_name, + .id_table = &service_id[0], + + .probe = aerdrv_load, + .remove = aerdrv_unload, + + .suspend = aerdrv_suspend, + .resume = aerdrv_resume, +}; + +Below is a sample code for registering/unregistering a service +driver. + +static int __init aerdrv_service_init(void) +{ + int retval = 0; + + retval = pcie_port_service_register(&root_aerdrv); + if (!retval) { + /* + * FIX ME + */ + } + return retval; +} + +static void __exit aerdrv_service_exit(void) +{ + pcie_port_service_unregister(&root_aerdrv); +} + +module_init(aerdrv_service_init); +module_exit(aerdrv_service_exit); + +6. Possible Resource Conflicts + +Since all service drivers of a PCI-PCI Bridge Port device are +allowed to run simultaneously, below lists a few of possible resource +conflicts with proposed solutions. + +6.1 MSI Vector Resource + +The MSI capability structure enables a device software driver to call +pci_enable_msi to request MSI based interrupts. Once MSI interrupts +are enabled on a device, it stays in this mode until a device driver +calls pci_disable_msi to disable MSI interrupts and revert back to +INTx emulation mode. Since service drivers of the same PCI-PCI Bridge +port share the same physical device, if an individual service driver +calls pci_enable_msi/pci_disable_msi it may result unpredictable +behavior. For example, two service drivers run simultaneously on the +same physical Root Port. Both service drivers call pci_enable_msi to +request MSI based interrupts. A service driver may not know whether +any other service drivers have run on this Root Port. If either one +of them calls pci_disable_msi, it puts the other service driver +in a wrong interrupt mode. + +To avoid this situation all service drivers are not permitted to +switch interrupt mode on its device. The PCI Express Port Bus driver +is responsible for determining the interrupt mode and this should be +transparent to service drivers. Service drivers need to know only +the vector IRQ assigned to the field irq of struct pcie_device, which +is passed in when the PCI Express Port Bus driver probes each service +driver. Service drivers should use (struct pcie_device*)dev->irq to +call request_irq/free_irq. In addition, the interrupt mode is stored +in the field interrupt_mode of struct pcie_device. + +6.2 MSI-X Vector Resources + +Similar to the MSI a device driver for an MSI-X capable device can +call pci_enable_msix to request MSI-X interrupts. All service drivers +are not permitted to switch interrupt mode on its device. The PCI +Express Port Bus driver is responsible for determining the interrupt +mode and this should be transparent to service drivers. Any attempt +by service driver to call pci_enable_msix/pci_disable_msix may +result unpredictable behavior. Service drivers should use +(struct pcie_device*)dev->irq and call request_irq/free_irq. + +6.3 PCI Memory/IO Mapped Regions + +Service drivers for PCI Express Power Management (PME), Advanced +Error Reporting (AER), Hot-Plug (HP) and Virtual Channel (VC) access +PCI configuration space on the PCI Express port. In all cases the +registers accessed are independent of each other. This patch assumes +that all service drivers will be well behaved and not overwrite +other service driver's configuration settings. + +6.4 PCI Config Registers + +Each service driver runs its PCI config operations on its own +capability structure except the PCI Express capability structure, in +which Root Control register and Device Control register are shared +between PME and AER. This patch assumes that all service drivers +will be well behaved and not overwrite other service driver's +configuration settings. diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig --- a/arch/i386/Kconfig 2005-01-13 16:56:29 -08:00 +++ b/arch/i386/Kconfig 2005-01-13 16:56:29 -08:00 @@ -1132,6 +1132,8 @@ select ACPI_BOOT default y +source "drivers/pci/pcie/Kconfig" + source "drivers/pci/Kconfig" config ISA diff -Nru a/arch/i386/pci/pcbios.c b/arch/i386/pci/pcbios.c --- a/arch/i386/pci/pcbios.c 2005-01-13 16:56:29 -08:00 +++ b/arch/i386/pci/pcbios.c 2005-01-13 16:56:29 -08:00 @@ -385,8 +385,8 @@ } } if (!found) { - printk(KERN_WARNING "PCI: Device %02x:%02x not found by BIOS\n", - dev->bus->number, dev->devfn); + printk(KERN_WARNING "PCI: Device %s not found by BIOS\n", + pci_name(dev)); list_del(&dev->global_list); list_add_tail(&dev->global_list, &sorted_devices); } diff -Nru a/drivers/Makefile b/drivers/Makefile --- a/drivers/Makefile 2005-01-13 16:56:29 -08:00 +++ b/drivers/Makefile 2005-01-13 16:56:29 -08:00 @@ -55,6 +55,7 @@ obj-$(CONFIG_PHONE) += telephony/ obj-$(CONFIG_MD) += md/ obj-$(CONFIG_BT) += bluetooth/ +obj-$(CONFIG_PCIEPORTBUS) += pci/pcie/ obj-$(CONFIG_ISDN) += isdn/ obj-$(CONFIG_MCA) += mca/ obj-$(CONFIG_EISA) += eisa/ diff -Nru a/drivers/pci/access.c b/drivers/pci/access.c --- a/drivers/pci/access.c 2005-01-13 16:56:29 -08:00 +++ b/drivers/pci/access.c 2005-01-13 16:56:29 -08:00 @@ -7,7 +7,7 @@ * configuration space. */ -static spinlock_t pci_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(pci_lock); /* * Wrappers for all PCI configuration access functions. They just check diff -Nru a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig --- a/drivers/pci/hotplug/Kconfig 2005-01-13 16:56:29 -08:00 +++ b/drivers/pci/hotplug/Kconfig 2005-01-13 16:56:29 -08:00 @@ -134,27 +134,6 @@ When in doubt, say N. -config HOTPLUG_PCI_PCIE - tristate "PCI Express Hotplug driver" - depends on HOTPLUG_PCI - help - Say Y here if you have a motherboard that supports PCI Express Native - Hotplug - - To compile this driver as a module, choose M here: the - module will be called pciehp. - - When in doubt, say N. - -config HOTPLUG_PCI_PCIE_POLL_EVENT_MODE - bool "Use polling mechanism for hot-plug events (for testing purpose)" - depends on HOTPLUG_PCI_PCIE - help - Say Y here if you want to use the polling mechanism for hot-plug - events for early platform testing. - - When in doubt, say N. - config HOTPLUG_PCI_SHPC tristate "SHPC PCI Hotplug driver" depends on HOTPLUG_PCI diff -Nru a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h --- a/drivers/pci/hotplug/pciehp.h 2005-01-13 16:56:29 -08:00 +++ b/drivers/pci/hotplug/pciehp.h 2005-01-13 16:56:29 -08:00 @@ -34,6 +34,7 @@ #include #include #include +#include #include "pci_hotplug.h" #define MY_NAME "pciehp" @@ -311,7 +312,7 @@ typedef u8(*php_intr_callback_t) (unsigned int change_id, void *instance_id); -int pcie_init(struct controller *ctrl, struct pci_dev *pdev, +int pcie_init(struct controller *ctrl, struct pcie_device *dev, php_intr_callback_t attention_button_callback, php_intr_callback_t switch_change_callback, php_intr_callback_t presence_change_callback, diff -Nru a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c --- a/drivers/pci/hotplug/pciehp_core.c 2005-01-13 16:56:29 -08:00 +++ b/drivers/pci/hotplug/pciehp_core.c 2005-01-13 16:56:29 -08:00 @@ -40,6 +40,7 @@ #include #include "pciehp.h" #include "pciehprm.h" +#include /* Global variables */ int pciehp_debug; @@ -346,7 +347,7 @@ return 0; } -static int pcie_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_id *id) { int rc; struct controller *ctrl; @@ -354,7 +355,9 @@ int first_device_num = 0 ; /* first PCI device number supported by this PCIE */ int num_ctlr_slots; /* number of slots supported by this HPC */ u8 value; - + struct pci_dev *pdev; + + dbg("%s: Called by hp_drv\n", __FUNCTION__); ctrl = kmalloc(sizeof(*ctrl), GFP_KERNEL); if (!ctrl) { err("%s : out of memory\n", __FUNCTION__); @@ -363,8 +366,10 @@ memset(ctrl, 0, sizeof(struct controller)); dbg("%s: DRV_thread pid = %d\n", __FUNCTION__, current->pid); + + pdev = dev->port; - rc = pcie_init(ctrl, pdev, + rc = pcie_init(ctrl, dev, (php_intr_callback_t) pciehp_handle_attention_button, (php_intr_callback_t) pciehp_handle_switch_change, (php_intr_callback_t) pciehp_handle_presence_change, @@ -562,32 +567,52 @@ } +int hpdriver_context = 0; -static struct pci_device_id pcied_pci_tbl[] = { - { - .class = ((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), - .class_mask = ~0, - .vendor = PCI_ANY_ID, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - - { /* end: all zeroes */ } -}; - -MODULE_DEVICE_TABLE(pci, pcied_pci_tbl); +static void pciehp_remove (struct pcie_device *device) +{ + printk("%s ENTRY\n", __FUNCTION__); + printk("%s -> Call free_irq for irq = %d\n", + __FUNCTION__, device->irq); + free_irq(device->irq, &hpdriver_context); +} +#ifdef CONFIG_PM +static int pciehp_suspend (struct pcie_device *dev, u32 state) +{ + printk("%s ENTRY\n", __FUNCTION__); + return 0; +} +static int pciehp_resume (struct pcie_device *dev) +{ + printk("%s ENTRY\n", __FUNCTION__); + return 0; +} +#endif -static struct pci_driver pcie_driver = { - .name = PCIE_MODULE_NAME, - .id_table = pcied_pci_tbl, - .probe = pcie_probe, - /* remove: pcie_remove_one, */ +static struct pcie_port_service_id port_pci_ids[] = { { + .vendor = PCI_ANY_ID, + .device = PCI_ANY_ID, + .port_type = PCIE_RC_PORT, + .service_type = PCIE_PORT_SERVICE_HP, + .driver_data = 0, + }, { /* end: all zeroes */ } }; +static const char device_name[] = "hpdriver"; - +static struct pcie_port_service_driver hpdriver_portdrv = { + .name = (char *)device_name, + .id_table = &port_pci_ids[0], + + .probe = pciehp_probe, + .remove = pciehp_remove, + +#ifdef CONFIG_PM + .suspend = pciehp_suspend, + .resume = pciehp_resume, +#endif /* PM */ +}; static int __init pcied_init(void) { @@ -603,9 +628,11 @@ retval = pciehprm_init(PCI); if (!retval) { - retval = pci_register_driver(&pcie_driver); - dbg("pci_register_driver = %d\n", retval); - info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); + retval = pcie_port_service_register(&hpdriver_portdrv); + dbg("pcie_port_service_register = %d\n", retval); + info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); + if (retval) + dbg("%s: Failure to register service\n", __FUNCTION__); } error_hpc_init: @@ -625,8 +652,8 @@ pciehprm_cleanup(); - dbg("pci_unregister_driver\n"); - pci_unregister_driver(&pcie_driver); + dbg("pcie_port_service_unregister\n"); + pcie_port_service_unregister(&hpdriver_portdrv); info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); } diff -Nru a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c --- a/drivers/pci/hotplug/pciehp_hpc.c 2005-01-13 16:56:29 -08:00 +++ b/drivers/pci/hotplug/pciehp_hpc.c 2005-01-13 16:56:29 -08:00 @@ -1249,7 +1249,7 @@ }; int pcie_init(struct controller * ctrl, - struct pci_dev *pdev, + struct pcie_device *dev, php_intr_callback_t attention_button_callback, php_intr_callback_t switch_change_callback, php_intr_callback_t presence_change_callback, @@ -1265,6 +1265,7 @@ u32 slot_cap; int cap_base, saved_cap_base; u16 slot_status, slot_ctrl; + struct pci_dev *pdev; DBG_ENTER_ROUTINE @@ -1277,7 +1278,8 @@ } memset(php_ctlr, 0, sizeof(struct php_ctlr_state_s)); - + + pdev = dev->port; php_ctlr->pci_dev = pdev; /* save pci_dev in context */ dbg("%s: pdev->vendor %x pdev->device %x\n", __FUNCTION__, @@ -1338,7 +1340,7 @@ } dbg("pdev = %p: b:d:f:irq=0x%x:%x:%x:%x\n", pdev, pdev->bus->number, - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pdev->irq); + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq); for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) if (pci_resource_len(pdev, rc) > 0) dbg("pci resource[%d] start=0x%lx(len=0x%lx)\n", rc, @@ -1355,7 +1357,7 @@ init_waitqueue_head(&ctrl->queue); /* find the IRQ */ - php_ctlr->irq = pdev->irq; + php_ctlr->irq = dev->irq; dbg("HPC interrupt = %d\n", php_ctlr->irq); /* Save interrupt callback info */ @@ -1407,17 +1409,6 @@ start_int_poll_timer( php_ctlr, 10 ); /* start with 10 second delay */ } else { /* Installs the interrupt handler */ - dbg("%s: pcie_mch_quirk = %x\n", __FUNCTION__, pcie_mch_quirk); - if (!pcie_mch_quirk) { - rc = pci_enable_msi(pdev); - if (rc) { - info("Can't get msi for the hotplug controller\n"); - info("Use INTx for the hotplug controller\n"); - dbg("%s: rc = %x\n", __FUNCTION__, rc); - } else - php_ctlr->irq = pdev->irq; - } - rc = request_irq(php_ctlr->irq, pcie_isr, SA_SHIRQ, MY_NAME, (void *) ctrl); dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc); if (rc) { diff -Nru a/drivers/pci/msi.c b/drivers/pci/msi.c --- a/drivers/pci/msi.c 2005-01-13 16:56:29 -08:00 +++ b/drivers/pci/msi.c 2005-01-13 16:56:29 -08:00 @@ -22,7 +22,7 @@ #include "msi.h" -static spinlock_t msi_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(msi_lock); static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL }; static kmem_cache_t* msi_cachep; @@ -374,19 +374,18 @@ if ((status = msi_cache_init()) < 0) { pci_msi_enable = 0; - printk(KERN_INFO "WARNING: MSI INIT FAILURE\n"); + printk(KERN_WARNING "PCI: MSI cache init failed\n"); return status; } last_alloc_vector = assign_irq_vector(AUTO_ASSIGN); if (last_alloc_vector < 0) { pci_msi_enable = 0; - printk(KERN_INFO "WARNING: ALL VECTORS ARE BUSY\n"); + printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n"); status = -EBUSY; return status; } vector_irq[last_alloc_vector] = 0; nr_released_vectors++; - printk(KERN_INFO "MSI INIT SUCCESS\n"); return status; } @@ -736,7 +735,9 @@ /* Check whether driver already requested for MSI-X vectors */ if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSIX)) > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) { - printk(KERN_INFO "Can't enable MSI. Device already had MSI-X vectors assigned\n"); + printk(KERN_INFO "PCI: %s: Can't enable MSI. " + "Device already has MSI-X vectors assigned\n", + pci_name(dev)); dev->irq = temp; return -EINVAL; } @@ -774,9 +775,9 @@ } if (entry->msi_attrib.state) { spin_unlock_irqrestore(&msi_lock, flags); - printk(KERN_DEBUG "Driver[%d:%d:%d] unloaded wo doing free_irq on vector->%d\n", - dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), - dev->irq); + printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without " + "free_irq() on MSI vector %d\n", + pci_name(dev), dev->irq); BUG_ON(entry->msi_attrib.state > 0); } else { vector_irq[dev->irq] = 0; /* free it */ @@ -982,7 +983,9 @@ /* Check whether driver already requested for MSI vector */ if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSI)) { - printk(KERN_INFO "Can't enable MSI-X. Device already had MSI vector assigned\n"); + printk(KERN_INFO "PCI: %s: Can't enable MSI-X. " + "Device already has an MSI vector assigned\n", + pci_name(dev)); dev->irq = temp; return -EINVAL; } @@ -1050,9 +1053,9 @@ spin_unlock_irqrestore(&msi_lock, flags); if (warning) { dev->irq = temp; - printk(KERN_DEBUG "Driver[%d:%d:%d] unloaded wo doing free_irq on all vectors\n", - dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn)); + printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without " + "free_irq() on all MSI-X vectors\n", + pci_name(dev)); BUG_ON(warning > 0); } else { dev->irq = temp; @@ -1088,9 +1091,9 @@ state = msi_desc[dev->irq]->msi_attrib.state; spin_unlock_irqrestore(&msi_lock, flags); if (state) { - printk(KERN_DEBUG "Driver[%d:%d:%d] unloaded wo doing free_irq on vector->%d\n", - dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), dev->irq); + printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " + "called without free_irq() on MSI vector %d\n", + pci_name(dev), dev->irq); BUG_ON(state > 0); } else /* Release MSI vector assigned to this device */ msi_free_vector(dev, dev->irq, 0); @@ -1132,9 +1135,9 @@ iounmap(base); release_mem_region(phys_addr, PCI_MSIX_ENTRY_SIZE * multi_msix_capable(control)); - printk(KERN_DEBUG "Driver[%d:%d:%d] unloaded wo doing free_irq on all vectors\n", - dev->bus->number, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn)); + printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " + "called without free_irq() on all MSI-X vectors\n", + pci_name(dev)); BUG_ON(warning > 0); } dev->irq = temp; /* Restore IOAPIC IRQ */ diff -Nru a/drivers/pci/pci.c b/drivers/pci/pci.c --- a/drivers/pci/pci.c 2005-01-13 16:56:29 -08:00 +++ b/drivers/pci/pci.c 2005-01-13 16:56:29 -08:00 @@ -269,7 +269,7 @@ pci_read_config_word(dev,pm + PCI_PM_PMC,&pmc); if ((pmc & PCI_PM_CAP_VER_MASK) != 2) { - printk(KERN_WARNING + printk(KERN_DEBUG "PCI: %s has unsupported PM cap regs version (%u)\n", dev->slot_name, pmc & PCI_PM_CAP_VER_MASK); return -EIO; diff -Nru a/drivers/pci/pci.h b/drivers/pci/pci.h --- a/drivers/pci/pci.h 2005-01-13 16:56:29 -08:00 +++ b/drivers/pci/pci.h 2005-01-13 16:56:29 -08:00 @@ -59,12 +59,14 @@ extern int pci_visit_dev(struct pci_visit *fn, struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_parent); +extern void pci_remove_legacy_files(struct pci_bus *bus); /* Lock for read/write access to pci device and bus lists */ extern spinlock_t pci_bus_lock; extern int pcie_mch_quirk; extern struct device_attribute pci_dev_attrs[]; +extern struct class_device_attribute class_device_attr_cpuaffinity; /** * pci_match_one_device - Tell if a PCI device structure has a matching diff -Nru a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/pci/pcie/Kconfig 2005-01-13 16:56:29 -08:00 @@ -0,0 +1,38 @@ +# +# PCI Express Port Bus Configuration +# +config PCIEPORTBUS + bool "PCI Express support" + depends on PCI_GOMMCONFIG || PCI_GOANY + default n + + ---help--- + This automatically enables PCI Express Port Bus support. Users can + choose Native Hot-Plug support, Advanced Error Reporting support, + Power Management Event support and Virtual Channel support to run + on PCI Express Ports (Root or Switch). + +# +# Include service Kconfig here +# +config HOTPLUG_PCI_PCIE + tristate "PCI Express Hotplug driver" + depends on HOTPLUG_PCI && PCIEPORTBUS + help + Say Y here if you have a motherboard that supports PCI Express Native + Hotplug + + To compile this driver as a module, choose M here: the + module will be called pciehp. + + When in doubt, say N. + +config HOTPLUG_PCI_PCIE_POLL_EVENT_MODE + bool "Use polling mechanism for hot-plug events (for testing purpose)" + depends on HOTPLUG_PCI_PCIE + help + Say Y here if you want to use the polling mechanism for hot-plug + events for early platform testing. + + When in doubt, say N. + diff -Nru a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/pci/pcie/Makefile 2005-01-13 16:56:29 -08:00 @@ -0,0 +1,7 @@ +# +# Makefile for PCI-Express PORT Driver +# + +pcieportdrv-y := portdrv_core.o portdrv_pci.o portdrv_bus.o + +obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o diff -Nru a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/pci/pcie/portdrv.h 2005-01-13 16:56:29 -08:00 @@ -0,0 +1,42 @@ +/* + * File: portdrv.h + * Purpose: PCI Express Port Bus Driver's Internal Data Structures + * + * Copyright (C) 2004 Intel + * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) + */ + +#ifndef _PORTDRV_H_ +#define _PORTDRV_H_ + +#if !defined(PCI_CAP_ID_PME) +#define PCI_CAP_ID_PME 1 +#endif + +#if !defined(PCI_CAP_ID_EXP) +#define PCI_CAP_ID_EXP 0x10 +#endif + +#define PORT_TYPE_MASK 0xf +#define PORT_TO_SLOT_MASK 0x100 +#define SLOT_HP_CAPABLE_MASK 0x40 +#define PCIE_CAPABILITIES_REG 0x2 +#define PCIE_SLOT_CAPABILITIES_REG 0x14 +#define PCIE_PORT_DEVICE_MAXSERVICES 4 +#define PCI_CFG_SPACE_SIZE 256 + +#define get_descriptor_id(type, service) (((type - 4) << 4) | service) + +extern struct bus_type pcie_port_bus_type; +extern struct device_driver pcieport_generic_driver; +extern int pcie_port_device_probe(struct pci_dev *dev); +extern int pcie_port_device_register(struct pci_dev *dev); +#ifdef CONFIG_PM +extern int pcie_port_device_suspend(struct pcie_device *dev, u32 state); +extern int pcie_port_device_resume(struct pcie_device *dev); +#endif +extern void pcie_port_device_remove(struct pcie_device *dev); +extern void pcie_port_bus_register(void); +extern void pcie_port_bus_unregister(void); + +#endif /* _PORTDRV_H_ */ diff -Nru a/drivers/pci/pcie/portdrv_bus.c b/drivers/pci/pcie/portdrv_bus.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/pci/pcie/portdrv_bus.c 2005-01-13 16:56:29 -08:00 @@ -0,0 +1,88 @@ +/* + * File: portdrv_bus.c + * Purpose: PCI Express Port Bus Driver's Bus Overloading Functions + * + * Copyright (C) 2004 Intel + * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) + */ + +#include +#include +#include +#include +#include + +#include + +static int generic_probe (struct device *dev) { return 0;} +static int generic_remove (struct device *dev) { return 0;} +static int pcie_port_bus_match(struct device *dev, struct device_driver *drv); +static int pcie_port_bus_suspend(struct device *dev, u32 state); +static int pcie_port_bus_resume(struct device *dev); + +struct bus_type pcie_port_bus_type = { + .name = "pci_express", + .match = pcie_port_bus_match, + .suspend = pcie_port_bus_suspend, + .resume = pcie_port_bus_resume, +}; + +struct device_driver pcieport_generic_driver = { + .name = "pcieport", + .bus = &pcie_port_bus_type, + .probe = generic_probe, + .remove = generic_remove, +}; + +static int pcie_port_bus_match(struct device *dev, struct device_driver *drv) +{ + struct pcie_device *pciedev; + struct pcie_port_service_driver *driver; + + if ( drv->bus != &pcie_port_bus_type || + dev->bus != &pcie_port_bus_type || + drv == &pcieport_generic_driver) { + return 0; + } + pciedev = to_pcie_device(dev); + driver = to_service_driver(drv); + if ( (driver->id_table->vendor != PCI_ANY_ID && + driver->id_table->vendor != pciedev->id.vendor) || + (driver->id_table->device != PCI_ANY_ID && + driver->id_table->device != pciedev->id.device) || + driver->id_table->port_type != pciedev->id.port_type || + driver->id_table->service_type != pciedev->id.service_type ) + return 0; + + return 1; +} + +static int pcie_port_bus_suspend(struct device *dev, u32 state) +{ + struct pcie_device *pciedev; + struct pcie_port_service_driver *driver; + + if (!dev || !dev->driver) + return 0; + + pciedev = to_pcie_device(dev); + driver = to_service_driver(dev->driver); + if (driver && driver->suspend) + driver->suspend(pciedev, state); + return 0; +} + +static int pcie_port_bus_resume(struct device *dev) +{ + struct pcie_device *pciedev; + struct pcie_port_service_driver *driver; + + if (!dev || !dev->driver) + return 0; + + pciedev = to_pcie_device(dev); + driver = to_service_driver(dev->driver); + if (driver && driver->resume) + driver->resume(pciedev); + return 0; +} diff -Nru a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/pci/pcie/portdrv_core.c 2005-01-13 16:56:29 -08:00 @@ -0,0 +1,453 @@ +/* + * File: portdrv_core.c + * Purpose: PCI Express Port Bus Driver's Core Functions + * + * Copyright (C) 2004 Intel + * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) + */ + +#include +#include +#include +#include +#include +#include + +#include "portdrv.h" + +extern int pcie_mch_quirk; /* MSI-quirk Indicator */ + +extern struct device_driver pcieport_generic_driver; + +static int pcie_port_probe_service(struct device *dev) +{ + struct pcie_device *pciedev; + struct pcie_port_service_driver *driver; + int status = -ENODEV; + + if (!dev || !dev->driver) + return status; + + driver = to_service_driver(dev->driver); + if (!driver || !driver->probe) + return status; + + pciedev = to_pcie_device(dev); + status = driver->probe(pciedev, driver->id_table); + if (!status) { + printk(KERN_DEBUG "Load service driver %s on pcie device %s\n", + driver->name, dev->bus_id); + get_device(dev); + } + return status; +} + +static int pcie_port_remove_service(struct device *dev) +{ + struct pcie_device *pciedev; + struct pcie_port_service_driver *driver; + + if (!dev || !dev->driver) + return 0; + + pciedev = to_pcie_device(dev); + driver = to_service_driver(dev->driver); + if (driver && driver->remove) { + printk(KERN_DEBUG "Unload service driver %s on pcie device %s\n", + driver->name, dev->bus_id); + driver->remove(pciedev); + put_device(dev); + } + return 0; +} + +static void pcie_port_shutdown_service(struct device *dev) {} + +static int pcie_port_suspend_service(struct device *dev, u32 state, u32 level) +{ + struct pcie_device *pciedev; + struct pcie_port_service_driver *driver; + + if (!dev || !dev->driver) + return 0; + + pciedev = to_pcie_device(dev); + driver = to_service_driver(dev->driver); + if (driver && driver->suspend) + driver->suspend(pciedev, state); + return 0; +} + +static int pcie_port_resume_service(struct device *dev, u32 state) +{ + struct pcie_device *pciedev; + struct pcie_port_service_driver *driver; + + if (!dev || !dev->driver) + return 0; + + pciedev = to_pcie_device(dev); + driver = to_service_driver(dev->driver); + + if (driver && driver->resume) + driver->resume(pciedev); + return 0; +} + +/* + * release_pcie_device + * + * Being invoked automatically when device is being removed + * in response to device_unregister(dev) call. + * Release all resources being claimed. + */ +static void release_pcie_device(struct device *dev) +{ + kfree(to_pcie_device(dev)); +} + +static int is_msi_quirked(struct pci_dev *dev) +{ + int port_type, quirk = 0; + u16 reg16; + + pci_read_config_word(dev, + pci_find_capability(dev, PCI_CAP_ID_EXP) + + PCIE_CAPABILITIES_REG, ®16); + port_type = (reg16 >> 4) & PORT_TYPE_MASK; + switch(port_type) { + case PCIE_RC_PORT: + if (pcie_mch_quirk == 1) + quirk = 1; + break; + case PCIE_SW_UPSTREAM_PORT: + case PCIE_SW_DOWNSTREAM_PORT: + default: + break; + } + return quirk; +} + +static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask) +{ + int i, pos, nvec, status = -EINVAL; + int interrupt_mode = PCIE_PORT_INTx_MODE; + + /* Set INTx as default */ + for (i = 0, nvec = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) { + if (mask & (1 << i)) + nvec++; + vectors[i] = dev->irq; + } + + /* Check MSI quirk */ + if (is_msi_quirked(dev)) + return interrupt_mode; + + /* Select MSI-X over MSI if supported */ + pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); + if (pos) { + struct msix_entry msix_entries[PCIE_PORT_DEVICE_MAXSERVICES] = + {{0, 0}, {0, 1}, {0, 2}, {0, 3}}; + printk("%s Found MSIX capability\n", __FUNCTION__); + status = pci_enable_msix(dev, msix_entries, nvec); + if (!status) { + int j = 0; + + interrupt_mode = PCIE_PORT_MSIX_MODE; + for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) { + if (mask & (1 << i)) + vectors[i] = msix_entries[j++].vector; + } + } + } + if (status) { + pos = pci_find_capability(dev, PCI_CAP_ID_MSI); + if (pos) { + printk("%s Found MSI capability\n", __FUNCTION__); + status = pci_enable_msi(dev); + if (!status) { + interrupt_mode = PCIE_PORT_MSI_MODE; + for (i = 0;i < PCIE_PORT_DEVICE_MAXSERVICES;i++) + vectors[i] = dev->irq; + } + } + } + return interrupt_mode; +} + +static int get_port_device_capability(struct pci_dev *dev) +{ + int services = 0, pos; + u16 reg16; + u32 reg32; + + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, ®16); + /* Hot-Plug Capable */ + if (reg16 & PORT_TO_SLOT_MASK) { + pci_read_config_dword(dev, + pos + PCIE_SLOT_CAPABILITIES_REG, ®32); + if (reg32 & SLOT_HP_CAPABLE_MASK) + services |= PCIE_PORT_SERVICE_HP; + } + /* PME Capable */ + pos = pci_find_capability(dev, PCI_CAP_ID_PME); + if (pos) + services |= PCIE_PORT_SERVICE_PME; + + pos = PCI_CFG_SPACE_SIZE; + while (pos) { + pci_read_config_dword(dev, pos, ®32); + switch (reg32 & 0xffff) { + case PCI_EXT_CAP_ID_ERR: + services |= PCIE_PORT_SERVICE_AER; + pos = reg32 >> 20; + break; + case PCI_EXT_CAP_ID_VC: + services |= PCIE_PORT_SERVICE_VC; + pos = reg32 >> 20; + break; + default: + pos = 0; + break; + } + } + + return services; +} + +static void pcie_device_init(struct pcie_device *parent, + struct pcie_device *dev, + int port_type, int service_type) +{ + struct device *device; + + if (parent) { + dev->id.vendor = parent->port->vendor; + dev->id.device = parent->port->device; + dev->id.port_type = port_type; + dev->id.service_type = (1 << service_type); + } + + /* Initialize generic device interface */ + device = &dev->device; + memset(device, 0, sizeof(struct device)); + INIT_LIST_HEAD(&device->node); + INIT_LIST_HEAD(&device->children); + INIT_LIST_HEAD(&device->bus_list); + device->bus = &pcie_port_bus_type; + device->driver = NULL; + device->driver_data = NULL; + device->release = release_pcie_device; /* callback to free pcie dev */ + sprintf(&device->bus_id[0], "%s.%02x", parent->device.bus_id, + get_descriptor_id(port_type, service_type)); + device->parent = ((parent == NULL) ? NULL : &parent->device); +} + +static struct pcie_device* alloc_pcie_device( + struct pcie_device *parent, struct pci_dev *bridge, + int port_type, int service_type, int irq, int irq_mode) +{ + struct pcie_device *device; + static int NR_PORTS = 0; + + device = kmalloc(sizeof(struct pcie_device), GFP_KERNEL); + if (!device) + return NULL; + + memset(device, 0, sizeof(struct pcie_device)); + device->port = bridge; + device->interrupt_mode = irq_mode; + device->irq = irq; + if (!parent) { + pcie_device_init(NULL, device, port_type, service_type); + NR_PORTS++; + device->device.driver = &pcieport_generic_driver; + sprintf(&device->device.bus_id[0], "port%d", NR_PORTS); + } else { + pcie_device_init(parent, device, port_type, service_type); + } + printk(KERN_DEBUG "Allocate Port Device[%s]\n", device->device.bus_id); + return device; +} + +int pcie_port_device_probe(struct pci_dev *dev) +{ + int pos, type; + u16 reg; + + if (!(pos = pci_find_capability(dev, PCI_CAP_ID_EXP))) + return -ENODEV; + + pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, ®); + type = (reg >> 4) & PORT_TYPE_MASK; + if ( type == PCIE_RC_PORT || type == PCIE_SW_UPSTREAM_PORT || + type == PCIE_SW_DOWNSTREAM_PORT ) + return 0; + + return -ENODEV; +} + +int pcie_port_device_register(struct pci_dev *dev) +{ + struct pcie_device *parent; + int status, type, capabilities, irq_mode, i; + int vectors[PCIE_PORT_DEVICE_MAXSERVICES]; + u16 reg16; + + /* Get port type */ + pci_read_config_word(dev, + pci_find_capability(dev, PCI_CAP_ID_EXP) + + PCIE_CAPABILITIES_REG, ®16); + type = (reg16 >> 4) & PORT_TYPE_MASK; + + /* Now get port services */ + capabilities = get_port_device_capability(dev); + irq_mode = assign_interrupt_mode(dev, vectors, capabilities); + + /* Allocate parent */ + parent = alloc_pcie_device(NULL, dev, type, 0, dev->irq, irq_mode); + if (!parent) + return -ENOMEM; + + status = device_register(&parent->device); + if (status) { + kfree(parent); + return status; + } + get_device(&parent->device); + pci_set_drvdata(dev, parent); + + /* Allocate child services if any */ + for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) { + struct pcie_device *child; + + if (capabilities & (1 << i)) { + child = alloc_pcie_device( + parent, /* parent */ + dev, /* Root/Upstream/Downstream */ + type, /* port type */ + i, /* service type */ + vectors[i], /* irq */ + irq_mode /* interrupt mode */); + if (child) { + status = device_register(&child->device); + if (status) { + kfree(child); + continue; + } + get_device(&child->device); + } + } + } + return 0; +} + +#ifdef CONFIG_PM +int pcie_port_device_suspend(struct pcie_device *dev, u32 state) +{ + struct list_head *head; + struct device *parent, *child; + struct device_driver *driver; + struct pcie_port_service_driver *service_driver; + + parent = &dev->device; + head = &parent->children; + while (!list_empty(head)) { + child = container_of(head->next, struct device, node); + driver = child->driver; + if (!driver) + continue; + service_driver = to_service_driver(driver); + if (service_driver->suspend) + service_driver->suspend(to_pcie_device(child), state); + } + return 0; +} + +int pcie_port_device_resume(struct pcie_device *dev) +{ + struct list_head *head; + struct device *parent, *child; + struct device_driver *driver; + struct pcie_port_service_driver *service_driver; + + parent = &dev->device; + head = &parent->children; + while (!list_empty(head)) { + child = container_of(head->next, struct device, node); + driver = child->driver; + if (!driver) + continue; + service_driver = to_service_driver(driver); + if (service_driver->resume) + service_driver->resume(to_pcie_device(child)); + } + return 0; + +} +#endif + +void pcie_port_device_remove(struct pcie_device *dev) +{ + struct list_head *head; + struct device *parent, *child; + struct device_driver *driver; + struct pcie_port_service_driver *service_driver; + + parent = &dev->device; + head = &parent->children; + while (!list_empty(head)) { + child = container_of(head->next, struct device, node); + driver = child->driver; + if (driver) { + service_driver = to_service_driver(driver); + if (service_driver->remove) + service_driver->remove(to_pcie_device(child)); + } + put_device(child); + device_unregister(child); + } + + /* Switch to INTx by default if MSI enabled */ + if (dev->interrupt_mode == PCIE_PORT_MSIX_MODE) + pci_disable_msix(dev->port); + else if (dev->interrupt_mode == PCIE_PORT_MSI_MODE) + pci_disable_msi(dev->port); + put_device(parent); + device_unregister(parent); +} + +void pcie_port_bus_register(void) +{ + bus_register(&pcie_port_bus_type); + driver_register(&pcieport_generic_driver); +} + +void pcie_port_bus_unregister(void) +{ + driver_unregister(&pcieport_generic_driver); + bus_unregister(&pcie_port_bus_type); +} + +int pcie_port_service_register(struct pcie_port_service_driver *new) +{ + new->driver.name = (char *)new->name; + new->driver.bus = &pcie_port_bus_type; + new->driver.probe = pcie_port_probe_service; + new->driver.remove = pcie_port_remove_service; + new->driver.shutdown = pcie_port_shutdown_service; + new->driver.suspend = pcie_port_suspend_service; + new->driver.resume = pcie_port_resume_service; + + return driver_register(&new->driver); +} + +void pcie_port_service_unregister(struct pcie_port_service_driver *new) +{ + driver_unregister(&new->driver); +} + +EXPORT_SYMBOL(pcie_port_service_register); +EXPORT_SYMBOL(pcie_port_service_unregister); diff -Nru a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/pci/pcie/portdrv_pci.c 2005-01-13 16:56:29 -08:00 @@ -0,0 +1,138 @@ +/* + * File: portdrv_pci.c + * Purpose: PCI Express Port Bus Driver + * + * Copyright (C) 2004 Intel + * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "portdrv.h" + +/* + * Version Information + */ +#define DRIVER_VERSION "v1.0" +#define DRIVER_AUTHOR "tom.l.nguyen@intel.com" +#define DRIVER_DESC "PCIE Port Bus Driver" +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +/* global data */ +static const char device_name[] = "pcieport-driver"; + +/* + * pcie_portdrv_probe - Probe PCI-Express port devices + * @dev: PCI-Express port device being probed + * + * If detected invokes the pcie_port_device_register() method for + * this port device. + * + */ +static int __devinit pcie_portdrv_probe (struct pci_dev *dev, + const struct pci_device_id *id ) +{ + int status; + + status = pcie_port_device_probe(dev); + if (status) + return status; + + if (pci_enable_device(dev) < 0) + return -ENODEV; + + pci_set_master(dev); + if (!dev->irq) { + printk(KERN_WARNING + "%s->Dev[%04x:%04x] has invalid IRQ. Check vendor BIOS\n", + __FUNCTION__, dev->device, dev->vendor); + } + if (pcie_port_device_register(dev)) + return -ENOMEM; + + return 0; +} + +static void pcie_portdrv_remove (struct pci_dev *dev) +{ + struct pcie_device *pciedev; + + pciedev = (struct pcie_device *)pci_get_drvdata(dev); + if (pciedev) { + pcie_port_device_remove(pciedev); + pci_set_drvdata(dev, NULL); + } +} + +#ifdef CONFIG_PM +static int pcie_portdrv_suspend (struct pci_dev *dev, u32 state) +{ + struct pcie_device *pciedev; + + pciedev = (struct pcie_device *)pci_get_drvdata(dev); + if (pciedev) + pcie_port_device_suspend(pciedev, state); + return 0; +} + +static int pcie_portdrv_resume (struct pci_dev *dev) +{ + struct pcie_device *pciedev; + + pciedev = (struct pcie_device *)pci_get_drvdata(dev); + if (pciedev) + pcie_port_device_resume(pciedev); + return 0; +} +#endif + +/* + * LINUX Device Driver Model + */ +static const struct pci_device_id port_pci_ids[] = { { + /* handle any PCI-Express port */ + PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), ~0), + }, { /* end: all zeroes */ } +}; +MODULE_DEVICE_TABLE(pci, port_pci_ids); + +static struct pci_driver pcie_portdrv = { + .name = (char *)device_name, + .id_table = &port_pci_ids[0], + + .probe = pcie_portdrv_probe, + .remove = pcie_portdrv_remove, + +#ifdef CONFIG_PM + .suspend = pcie_portdrv_suspend, + .resume = pcie_portdrv_resume, +#endif /* PM */ +}; + +static int __init pcie_portdrv_init(void) +{ + int retval = 0; + + pcie_port_bus_register(); + retval = pci_module_init(&pcie_portdrv); + if (retval) + pcie_port_bus_unregister(); + return retval; +} + +static void __exit pcie_portdrv_exit(void) +{ + pci_unregister_driver(&pcie_portdrv); + pcie_port_bus_unregister(); +} + +module_init(pcie_portdrv_init); +module_exit(pcie_portdrv_exit); diff -Nru a/drivers/pci/probe.c b/drivers/pci/probe.c --- a/drivers/pci/probe.c 2005-01-13 16:56:29 -08:00 +++ b/drivers/pci/probe.c 2005-01-13 16:56:29 -08:00 @@ -62,7 +62,7 @@ } } -static void pci_remove_legacy_files(struct pci_bus *b) +void pci_remove_legacy_files(struct pci_bus *b) { class_device_remove_bin_file(&b->class_dev, b->legacy_io); class_device_remove_bin_file(&b->class_dev, b->legacy_mem); @@ -70,7 +70,7 @@ } #else /* !HAVE_PCI_LEGACY */ static inline void pci_create_legacy_files(struct pci_bus *bus) { return; } -static inline void pci_remove_legacy_files(struct pci_bus *bus) { return; } +void pci_remove_legacy_files(struct pci_bus *bus) { return; } #endif /* HAVE_PCI_LEGACY */ /* @@ -86,7 +86,7 @@ buf[ret++] = '\n'; return ret; } -static CLASS_DEVICE_ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpuaffinity, NULL); +CLASS_DEVICE_ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpuaffinity, NULL); /* * PCI Bus Class @@ -95,10 +95,6 @@ { struct pci_bus *pci_bus = to_pci_bus(class_dev); - pci_remove_legacy_files(pci_bus); - class_device_remove_file(&pci_bus->class_dev, - &class_device_attr_cpuaffinity); - sysfs_remove_link(&pci_bus->class_dev.kobj, "bridge"); if (pci_bus->bridge) put_device(pci_bus->bridge); kfree(pci_bus); diff -Nru a/drivers/pci/remove.c b/drivers/pci/remove.c --- a/drivers/pci/remove.c 2005-01-13 16:56:29 -08:00 +++ b/drivers/pci/remove.c 2005-01-13 16:56:29 -08:00 @@ -61,15 +61,18 @@ } EXPORT_SYMBOL(pci_remove_device_safe); -void pci_remove_bus(struct pci_bus *b) +void pci_remove_bus(struct pci_bus *pci_bus) { - pci_proc_detach_bus(b); + pci_proc_detach_bus(pci_bus); spin_lock(&pci_bus_lock); - list_del(&b->node); + list_del(&pci_bus->node); spin_unlock(&pci_bus_lock); - - class_device_unregister(&b->class_dev); + pci_remove_legacy_files(pci_bus); + class_device_remove_file(&pci_bus->class_dev, + &class_device_attr_cpuaffinity); + sysfs_remove_link(&pci_bus->class_dev.kobj, "bridge"); + class_device_unregister(&pci_bus->class_dev); } EXPORT_SYMBOL(pci_remove_bus); diff -Nru a/drivers/pci/rom.c b/drivers/pci/rom.c --- a/drivers/pci/rom.c 2005-01-13 16:56:29 -08:00 +++ b/drivers/pci/rom.c 2005-01-13 16:56:29 -08:00 @@ -5,10 +5,7 @@ * (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes * * PCI ROM access routines - * */ - - #include #include #include @@ -24,11 +21,10 @@ * between the ROM and other resources, so enabling it may disable access * to MMIO registers or other card memory. */ -static void -pci_enable_rom(struct pci_dev *pdev) +static void pci_enable_rom(struct pci_dev *pdev) { u32 rom_addr; - + pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr); rom_addr |= PCI_ROM_ADDRESS_ENABLE; pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr); @@ -41,8 +37,7 @@ * Disable ROM decoding on a PCI device by turning off the last bit in the * ROM BAR. */ -static void -pci_disable_rom(struct pci_dev *pdev) +static void pci_disable_rom(struct pci_dev *pdev) { u32 rom_addr; pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr); @@ -57,7 +52,7 @@ * @return: kernel virtual pointer to image of ROM * * Map a PCI ROM into kernel space. If ROM is boot video ROM, - * the shadow BIOS copy will be returned instead of the + * the shadow BIOS copy will be returned instead of the * actual ROM. */ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) @@ -67,10 +62,12 @@ void __iomem *rom; void __iomem *image; int last_image; - - if (res->flags & IORESOURCE_ROM_SHADOW) { /* IORESOURCE_ROM_SHADOW only set on x86 */ - start = (loff_t)0xC0000; /* primary video rom always starts here */ - *size = 0x20000; /* cover C000:0 through E000:0 */ + + /* IORESOURCE_ROM_SHADOW only set on x86 */ + if (res->flags & IORESOURCE_ROM_SHADOW) { + /* primary video rom always starts here */ + start = (loff_t)0xC0000; + *size = 0x20000; /* cover C000:0 through E000:0 */ } else { if (res->flags & IORESOURCE_ROM_COPY) { *size = pci_resource_len(pdev, PCI_ROM_RESOURCE); @@ -79,28 +76,32 @@ /* assign the ROM an address if it doesn't have one */ if (res->parent == NULL) pci_assign_resource(pdev, PCI_ROM_RESOURCE); - + start = pci_resource_start(pdev, PCI_ROM_RESOURCE); *size = pci_resource_len(pdev, PCI_ROM_RESOURCE); if (*size == 0) return NULL; - + /* Enable ROM space decodes */ pci_enable_rom(pdev); } } - + rom = ioremap(start, *size); if (!rom) { /* restore enable if ioremap fails */ - if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW | IORESOURCE_ROM_COPY))) + if (!(res->flags & (IORESOURCE_ROM_ENABLE | + IORESOURCE_ROM_SHADOW | + IORESOURCE_ROM_COPY))) pci_disable_rom(pdev); return NULL; - } + } - /* Try to find the true size of the ROM since sometimes the PCI window */ - /* size is much larger than the actual size of the ROM. */ - /* True size is important if the ROM is going to be copied. */ + /* + * Try to find the true size of the ROM since sometimes the PCI window + * size is much larger than the actual size of the ROM. + * True size is important if the ROM is going to be copied. + */ image = rom; do { void __iomem *pds; @@ -136,30 +137,30 @@ * @return: kernel virtual pointer to image of ROM * * Map a PCI ROM into kernel space. If ROM is boot video ROM, - * the shadow BIOS copy will be returned instead of the + * the shadow BIOS copy will be returned instead of the * actual ROM. */ void __iomem *pci_map_rom_copy(struct pci_dev *pdev, size_t *size) { struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; void __iomem *rom; - + rom = pci_map_rom(pdev, size); if (!rom) return NULL; - + if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_SHADOW)) return rom; - + res->start = (unsigned long)kmalloc(*size, GFP_KERNEL); - if (!res->start) + if (!res->start) return rom; - res->end = res->start + *size; + res->end = res->start + *size; memcpy_fromio((void*)res->start, rom, *size); pci_unmap_rom(pdev, rom); res->flags |= IORESOURCE_ROM_COPY; - + return (void __iomem *)res->start; } @@ -170,16 +171,15 @@ * * Remove a mapping of a previously mapped ROM */ -void -pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom) +void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom) { struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; if (res->flags & IORESOURCE_ROM_COPY) return; - + iounmap(rom); - + /* Disable again before continuing, leave enabled if pci=rom */ if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW))) pci_disable_rom(pdev); @@ -189,26 +189,28 @@ * pci_remove_rom - disable the ROM and remove its sysfs attribute * @dev: pointer to pci device struct * + * Remove the rom file in sysfs and disable ROM decoding. */ -void -pci_remove_rom(struct pci_dev *pdev) +void pci_remove_rom(struct pci_dev *pdev) { struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; - + if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); - if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW | IORESOURCE_ROM_COPY))) + if (!(res->flags & (IORESOURCE_ROM_ENABLE | + IORESOURCE_ROM_SHADOW | + IORESOURCE_ROM_COPY))) pci_disable_rom(pdev); } /** - * pci_cleanup_rom - internal routine for freeing the ROM copy created + * pci_cleanup_rom - internal routine for freeing the ROM copy created * by pci_map_rom_copy called from remove.c * @dev: pointer to pci device struct * + * Free the copied ROM if we allocated one. */ -void -pci_cleanup_rom(struct pci_dev *pdev) +void pci_cleanup_rom(struct pci_dev *pdev) { struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; if (res->flags & IORESOURCE_ROM_COPY) { diff -Nru a/drivers/pci/search.c b/drivers/pci/search.c --- a/drivers/pci/search.c 2005-01-13 16:56:29 -08:00 +++ b/drivers/pci/search.c 2005-01-13 16:56:29 -08:00 @@ -13,7 +13,7 @@ #include #include "pci.h" -spinlock_t pci_bus_lock = SPIN_LOCK_UNLOCKED; +DEFINE_SPINLOCK(pci_bus_lock); static struct pci_bus * __devinit pci_do_find_bus(struct pci_bus* bus, unsigned char busnr) diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h --- a/include/linux/pci_ids.h 2005-01-13 16:56:29 -08:00 +++ b/include/linux/pci_ids.h 2005-01-13 16:56:29 -08:00 @@ -2244,7 +2244,7 @@ #define PCI_DEVICE_ID_INTEL_ICH6_17 0x266d #define PCI_DEVICE_ID_INTEL_ICH6_18 0x266e #define PCI_DEVICE_ID_INTEL_ICH6_19 0x266f -#define PCI_DEVICE_ID_INTEL_ICH7_0 0x27b0 +#define PCI_DEVICE_ID_INTEL_ICH7_0 0x27b8 #define PCI_DEVICE_ID_INTEL_ICH7_1 0x27b1 #define PCI_DEVICE_ID_INTEL_ICH7_2 0x27c0 #define PCI_DEVICE_ID_INTEL_ICH7_3 0x27c1 diff -Nru a/include/linux/pcieport_if.h b/include/linux/pcieport_if.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/include/linux/pcieport_if.h 2005-01-13 16:56:29 -08:00 @@ -0,0 +1,74 @@ +/* + * File: pcieport_if.h + * Purpose: PCI Express Port Bus Driver's IF Data Structure + * + * Copyright (C) 2004 Intel + * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) + */ + +#ifndef _PCIEPORT_IF_H_ +#define _PCIEPORT_IF_H_ + +/* Port Type */ +#define PCIE_RC_PORT 4 /* Root port of RC */ +#define PCIE_SW_UPSTREAM_PORT 5 /* Upstream port of Switch */ +#define PCIE_SW_DOWNSTREAM_PORT 6 /* Downstream port of Switch */ +#define PCIE_ANY_PORT 7 + +/* Service Type */ +#define PCIE_PORT_SERVICE_PME 1 /* Power Management Event */ +#define PCIE_PORT_SERVICE_AER 2 /* Advanced Error Reporting */ +#define PCIE_PORT_SERVICE_HP 4 /* Native Hotplug */ +#define PCIE_PORT_SERVICE_VC 8 /* Virtual Channel */ + +/* Root/Upstream/Downstream Port's Interrupt Mode */ +#define PCIE_PORT_INTx_MODE 0 +#define PCIE_PORT_MSI_MODE 1 +#define PCIE_PORT_MSIX_MODE 2 + +struct pcie_port_service_id { + __u32 vendor, device; /* Vendor and device ID or PCI_ANY_ID*/ + __u32 subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ + __u32 class, class_mask; /* (class,subclass,prog-if) triplet */ + __u32 port_type, service_type; /* Port Entity */ + kernel_ulong_t driver_data; +}; + +struct pcie_device { + int irq; /* Service IRQ/MSI/MSI-X Vector */ + int interrupt_mode; /* [0:INTx | 1:MSI | 2:MSI-X] */ + struct pcie_port_service_id id; /* Service ID */ + struct pci_dev *port; /* Root/Upstream/Downstream Port */ + void *priv_data; /* Service Private Data */ + struct device device; /* Generic Device Interface */ +}; +#define to_pcie_device(d) container_of(d, struct pcie_device, device) + +static inline void set_service_data(struct pcie_device *dev, void *data) +{ + dev->priv_data = data; +} + +static inline void* get_service_data(struct pcie_device *dev) +{ + return dev->priv_data; +} + +struct pcie_port_service_driver { + const char *name; + int (*probe) (struct pcie_device *dev, + const struct pcie_port_service_id *id); + void (*remove) (struct pcie_device *dev); + int (*suspend) (struct pcie_device *dev, u32 state); + int (*resume) (struct pcie_device *dev); + + const struct pcie_port_service_id *id_table; + struct device_driver driver; +}; +#define to_service_driver(d) \ + container_of(d, struct pcie_port_service_driver, driver) + +extern int pcie_port_service_register(struct pcie_port_service_driver *new); +extern void pcie_port_service_unregister(struct pcie_port_service_driver *new); + +#endif /* _PCIEPORT_IF_H_ */