diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/hotplug.c | 119 | ||||
-rw-r--r-- | drivers/pci/hotplug/cpci_hotplug.h | 2 | ||||
-rw-r--r-- | drivers/pci/hotplug/cpci_hotplug_core.c | 169 | ||||
-rw-r--r-- | drivers/pci/hotplug/cpci_hotplug_pci.c | 352 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp.h | 1 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_core.c | 2 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 156 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_core.c | 2 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_ctrl.c | 30 | ||||
-rw-r--r-- | drivers/pci/pci-sysfs.c | 12 | ||||
-rw-r--r-- | drivers/pci/pci.h | 27 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_bus.c | 3 | ||||
-rw-r--r-- | drivers/pci/quirks.c | 40 |
13 files changed, 257 insertions, 658 deletions
diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c index 021d0f76bc4..3903f8c559b 100644 --- a/drivers/pci/hotplug.c +++ b/drivers/pci/hotplug.c @@ -52,116 +52,17 @@ int pci_hotplug (struct device *dev, char **envp, int num_envp, if ((buffer_size - length <= 0) || (i >= num_envp)) return -ENOMEM; + envp[i++] = scratch; + length += scnprintf (scratch, buffer_size - length, + "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x\n", + pdev->vendor, pdev->device, + pdev->subsystem_vendor, pdev->subsystem_device, + (u8)(pdev->class >> 16), (u8)(pdev->class >> 8), + (u8)(pdev->class)); + if ((buffer_size - length <= 0) || (i >= num_envp)) + return -ENOMEM; + envp[i] = NULL; return 0; } - -static int pci_visit_bus (struct pci_visit * fn, struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_parent) -{ - struct list_head *ln; - struct pci_dev *dev; - struct pci_dev_wrapped wrapped_dev; - int result = 0; - - pr_debug("PCI: Scanning bus %04x:%02x\n", pci_domain_nr(wrapped_bus->bus), - wrapped_bus->bus->number); - - if (fn->pre_visit_pci_bus) { - result = fn->pre_visit_pci_bus(wrapped_bus, wrapped_parent); - if (result) - return result; - } - - ln = wrapped_bus->bus->devices.next; - while (ln != &wrapped_bus->bus->devices) { - dev = pci_dev_b(ln); - ln = ln->next; - - memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped)); - wrapped_dev.dev = dev; - - result = pci_visit_dev(fn, &wrapped_dev, wrapped_bus); - if (result) - return result; - } - - if (fn->post_visit_pci_bus) - result = fn->post_visit_pci_bus(wrapped_bus, wrapped_parent); - - return result; -} - -static int pci_visit_bridge (struct pci_visit * fn, - struct pci_dev_wrapped *wrapped_dev, - struct pci_bus_wrapped *wrapped_parent) -{ - struct pci_bus *bus; - struct pci_bus_wrapped wrapped_bus; - int result = 0; - - pr_debug("PCI: Scanning bridge %s\n", pci_name(wrapped_dev->dev)); - - if (fn->visit_pci_dev) { - result = fn->visit_pci_dev(wrapped_dev, wrapped_parent); - if (result) - return result; - } - - bus = wrapped_dev->dev->subordinate; - if (bus) { - memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped)); - wrapped_bus.bus = bus; - - result = pci_visit_bus(fn, &wrapped_bus, wrapped_dev); - } - return result; -} - -/** - * pci_visit_dev - scans the pci buses. - * @fn: callback functions that are called while visiting - * @wrapped_dev: the device to scan - * @wrapped_parent: the bus where @wrapped_dev is connected to - * - * Every bus and every function is presented to a custom - * function that can act upon it. - */ -int pci_visit_dev(struct pci_visit *fn, struct pci_dev_wrapped *wrapped_dev, - struct pci_bus_wrapped *wrapped_parent) -{ - struct pci_dev* dev = wrapped_dev ? wrapped_dev->dev : NULL; - int result = 0; - - if (!dev) - return 0; - - if (fn->pre_visit_pci_dev) { - result = fn->pre_visit_pci_dev(wrapped_dev, wrapped_parent); - if (result) - return result; - } - - switch (dev->class >> 8) { - case PCI_CLASS_BRIDGE_PCI: - result = pci_visit_bridge(fn, wrapped_dev, - wrapped_parent); - if (result) - return result; - break; - default: - pr_debug("PCI: Scanning device %s\n", pci_name(dev)); - if (fn->visit_pci_dev) { - result = fn->visit_pci_dev (wrapped_dev, - wrapped_parent); - if (result) - return result; - } - } - - if (fn->post_visit_pci_dev) - result = fn->post_visit_pci_dev(wrapped_dev, wrapped_parent); - - return result; -} -EXPORT_SYMBOL(pci_visit_dev); diff --git a/drivers/pci/hotplug/cpci_hotplug.h b/drivers/pci/hotplug/cpci_hotplug.h index 3ddd75937a4..d9769b30be9 100644 --- a/drivers/pci/hotplug/cpci_hotplug.h +++ b/drivers/pci/hotplug/cpci_hotplug.h @@ -31,7 +31,7 @@ #include <linux/types.h> #include <linux/pci.h> -/* PICMG 2.12 R2.0 HS CSR bits: */ +/* PICMG 2.1 R2.0 HS CSR bits: */ #define HS_CSR_INS 0x0080 #define HS_CSR_EXT 0x0040 #define HS_CSR_PI 0x0030 diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c index ed243605dc7..9e9dab7fe86 100644 --- a/drivers/pci/hotplug/cpci_hotplug_core.c +++ b/drivers/pci/hotplug/cpci_hotplug_core.c @@ -33,11 +33,11 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/smp_lock.h> +#include <asm/atomic.h> #include <linux/delay.h> #include "pci_hotplug.h" #include "cpci_hotplug.h" -#define DRIVER_VERSION "0.2" #define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>" #define DRIVER_DESC "CompactPCI Hot Plug Core" @@ -54,9 +54,10 @@ #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) /* local variables */ -static spinlock_t list_lock; +static DECLARE_RWSEM(list_rwsem); static LIST_HEAD(slot_list); static int slots; +static atomic_t extracting; int cpci_debug; static struct cpci_hp_controller *controller; static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ @@ -68,6 +69,8 @@ static int disable_slot(struct hotplug_slot *slot); static int set_attention_status(struct hotplug_slot *slot, u8 value); static int get_power_status(struct hotplug_slot *slot, u8 * value); static int get_attention_status(struct hotplug_slot *slot, u8 * value); +static int get_adapter_status(struct hotplug_slot *slot, u8 * value); +static int get_latch_status(struct hotplug_slot *slot, u8 * value); static struct hotplug_slot_ops cpci_hotplug_slot_ops = { .owner = THIS_MODULE, @@ -76,6 +79,8 @@ static struct hotplug_slot_ops cpci_hotplug_slot_ops = { .set_attention_status = set_attention_status, .get_power_status = get_power_status, .get_attention_status = get_attention_status, + .get_adapter_status = get_adapter_status, + .get_latch_status = get_latch_status, }; static int @@ -148,8 +153,10 @@ disable_slot(struct hotplug_slot *hotplug_slot) warn("failure to update adapter file"); } - slot->extracting = 0; - + if(slot->extracting) { + slot->extracting = 0; + atomic_dec(&extracting); + } return retval; } @@ -188,6 +195,20 @@ set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) return cpci_set_attention_status(hotplug_slot->private, status); } +static int +get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value) +{ + *value = hotplug_slot->info->adapter_status; + return 0; +} + +static int +get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value) +{ + *value = hotplug_slot->info->latch_status; + return 0; +} + static void release_slot(struct hotplug_slot *hotplug_slot) { struct slot *slot = hotplug_slot->private; @@ -273,10 +294,10 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) } /* Add slot to our internal list */ - spin_lock(&list_lock); + down_write(&list_rwsem); list_add(&slot->slot_list, &slot_list); slots++; - spin_unlock(&list_lock); + up_write(&list_rwsem); } return 0; error_name: @@ -299,9 +320,9 @@ cpci_hp_unregister_bus(struct pci_bus *bus) struct list_head *next; int status; - spin_lock(&list_lock); + down_write(&list_rwsem); if(!slots) { - spin_unlock(&list_lock); + up_write(&list_rwsem); return -1; } list_for_each_safe(tmp, next, &slot_list) { @@ -319,7 +340,7 @@ cpci_hp_unregister_bus(struct pci_bus *bus) slots--; } } - spin_unlock(&list_lock); + up_write(&list_rwsem); return 0; } @@ -347,7 +368,7 @@ cpci_hp_intr(int irq, void *data, struct pt_regs *regs) } /* - * According to PICMG 2.12 R2.0, section 6.3.2, upon + * According to PICMG 2.1 R2.0, section 6.3.2, upon * initialization, the system driver shall clear the * INS bits of the cold-inserted devices. */ @@ -359,9 +380,9 @@ init_slots(void) struct pci_dev* dev; dbg("%s - enter", __FUNCTION__); - spin_lock(&list_lock); + down_read(&list_rwsem); if(!slots) { - spin_unlock(&list_lock); + up_read(&list_rwsem); return -1; } list_for_each(tmp, &slot_list) { @@ -386,7 +407,7 @@ init_slots(void) } } } - spin_unlock(&list_lock); + up_read(&list_rwsem); dbg("%s - exit", __FUNCTION__); return 0; } @@ -398,10 +419,11 @@ check_slots(void) struct list_head *tmp; int extracted; int inserted; + u16 hs_csr; - spin_lock(&list_lock); + down_read(&list_rwsem); if(!slots) { - spin_unlock(&list_lock); + up_read(&list_rwsem); err("no slots registered, shutting down"); return -1; } @@ -411,8 +433,6 @@ check_slots(void) dbg("%s - looking at slot %s", __FUNCTION__, slot->hotplug_slot->name); if(cpci_check_and_clear_ins(slot)) { - u16 hs_csr; - /* Some broken hardware (e.g. PLX 9054AB) asserts ENUM# twice... */ if(slot->dev) { warn("slot %s already inserted", slot->hotplug_slot->name); @@ -462,8 +482,6 @@ check_slots(void) inserted++; } else if(cpci_check_ext(slot)) { - u16 hs_csr; - /* Process extraction request */ dbg("%s - slot %s extracted", __FUNCTION__, slot->hotplug_slot->name); @@ -476,20 +494,40 @@ check_slots(void) if(!slot->extracting) { if(update_latch_status(slot->hotplug_slot, 0)) { warn("failure to update latch file"); + } + atomic_inc(&extracting); slot->extracting = 1; } extracted++; + } else if(slot->extracting) { + hs_csr = cpci_get_hs_csr(slot); + if(hs_csr == 0xffff) { + /* + * Hmmm, we're likely hosed at this point, should we + * bother trying to tell the driver or not? + */ + err("card in slot %s was improperly removed", + slot->hotplug_slot->name); + if(update_adapter_status(slot->hotplug_slot, 0)) { + warn("failure to update adapter file"); + } + slot->extracting = 0; + atomic_dec(&extracting); + } } } - spin_unlock(&list_lock); + up_read(&list_rwsem); + dbg("inserted=%d, extracted=%d, extracting=%d", + inserted, extracted, atomic_read(&extracting)); if(inserted || extracted) { return extracted; } - else { + else if(!atomic_read(&extracting)) { err("cannot find ENUM# source, shutting down"); return -1; } + return 0; } /* This is the interrupt mode worker thread body */ @@ -497,8 +535,6 @@ static int event_thread(void *data) { int rc; - struct slot *slot; - struct list_head *tmp; lock_kernel(); daemonize("cpci_hp_eventd"); @@ -512,39 +548,22 @@ event_thread(void *data) thread_finished); if(thread_finished || signal_pending(current)) break; - while(controller->ops->query_enum()) { + do { rc = check_slots(); - if (rc > 0) + if (rc > 0) { /* Give userspace a chance to handle extraction */ msleep(500); - else if (rc < 0) { + } else if (rc < 0) { dbg("%s - error checking slots", __FUNCTION__); thread_finished = 1; break; } - } - /* Check for someone yanking out a board */ - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - if(slot->extracting) { - /* - * Hmmm, we're likely hosed at this point, should we - * bother trying to tell the driver or not? - */ - err("card in slot %s was improperly removed", - slot->hotplug_slot->name); - if(update_adapter_status(slot->hotplug_slot, 0)) { - warn("failure to update adapter file"); - } - slot->extracting = 0; - } - } + } while(atomic_read(&extracting) != 0); /* Re-enable ENUM# interrupt */ dbg("%s - re-enabling irq", __FUNCTION__); controller->ops->enable_irq(); } - dbg("%s - event thread signals exit", __FUNCTION__); up(&thread_exit); return 0; @@ -555,8 +574,6 @@ static int poll_thread(void *data) { int rc; - struct slot *slot; - struct list_head *tmp; lock_kernel(); daemonize("cpci_hp_polld"); @@ -565,35 +582,19 @@ poll_thread(void *data) while(1) { if(thread_finished || signal_pending(current)) break; - - while(controller->ops->query_enum()) { - rc = check_slots(); - if(rc > 0) - /* Give userspace a chance to handle extraction */ - msleep(500); - else if (rc < 0) { - dbg("%s - error checking slots", __FUNCTION__); - thread_finished = 1; - break; - } - } - /* Check for someone yanking out a board */ - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - if(slot->extracting) { - /* - * Hmmm, we're likely hosed at this point, should we - * bother trying to tell the driver or not? - */ - err("card in slot %s was improperly removed", - slot->hotplug_slot->name); - if(update_adapter_status(slot->hotplug_slot, 0)) { - warn("failure to update adapter file"); + if(controller->ops->query_enum()) { + do { + rc = check_slots(); + if(rc > 0) { + /* Give userspace a chance to handle extraction */ + msleep(500); + } else if(rc < 0) { + dbg("%s - error checking slots", __FUNCTION__); + thread_finished = 1; + break; } - slot->extracting = 0; - } + } while(atomic_read(&extracting) != 0); } - msleep(100); } dbg("poll thread signals exit"); @@ -667,6 +668,9 @@ cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller) int status = 0; if(controller) { + if(atomic_read(&extracting) != 0) { + return -EBUSY; + } if(!thread_finished) { cpci_stop_thread(); } @@ -691,12 +695,12 @@ cpci_hp_start(void) return -ENODEV; } - spin_lock(&list_lock); - if(!slots) { - spin_unlock(&list_lock); + down_read(&list_rwsem); + if(list_empty(&slot_list)) { + up_read(&list_rwsem); return -ENODEV; } - spin_unlock(&list_lock); + up_read(&list_rwsem); if(first) { status = init_slots(); @@ -727,7 +731,9 @@ cpci_hp_stop(void) if(!controller) { return -ENODEV; } - + if(atomic_read(&extracting) != 0) { + return -EBUSY; + } if(controller->irq) { /* Stop enum interrupt processing */ dbg("%s - disabling irq", __FUNCTION__); @@ -747,7 +753,7 @@ cleanup_slots(void) * Unregister all of our slots with the pci_hotplug subsystem, * and free up all memory that we had allocated. */ - spin_lock(&list_lock); + down_write(&list_rwsem); if(!slots) { goto null_cleanup; } @@ -761,17 +767,14 @@ cleanup_slots(void) kfree(slot); } null_cleanup: - spin_unlock(&list_lock); + up_write(&list_rwsem); return; } int __init cpci_hotplug_init(int debug) { - spin_lock_init(&list_lock); cpci_debug = debug; - - info(DRIVER_DESC " version: " DRIVER_VERSION); return 0; } diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c index 2e969616f29..69eb4fc54f2 100644 --- a/drivers/pci/hotplug/cpci_hotplug_pci.c +++ b/drivers/pci/hotplug/cpci_hotplug_pci.c @@ -32,11 +32,7 @@ #include "pci_hotplug.h" #include "cpci_hotplug.h" -#if !defined(MODULE) #define MY_NAME "cpci_hotplug" -#else -#define MY_NAME THIS_MODULE->name -#endif extern int cpci_debug; @@ -127,38 +123,6 @@ u16 cpci_get_hs_csr(struct slot* slot) return hs_csr; } -#if 0 -u16 cpci_set_hs_csr(struct slot* slot, u16 hs_csr) -{ - int hs_cap; - u16 new_hs_csr; - - hs_cap = pci_bus_find_capability(slot->bus, - slot->devfn, - PCI_CAP_ID_CHSWP); - if(!hs_cap) { - return 0xFFFF; - } - - /* Write out the new value */ - if(pci_bus_write_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - hs_csr)) { - return 0xFFFF; - } - - /* Read back what we just wrote out */ - if(pci_bus_read_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - &new_hs_csr)) { - return 0xFFFF; - } - return new_hs_csr; -} -#endif - int cpci_check_and_clear_ins(struct slot* slot) { int hs_cap; @@ -261,7 +225,6 @@ int cpci_led_on(struct slot* slot) return -ENODEV; } if((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) { - /* Set LOO */ hs_csr |= HS_CSR_LOO; if(pci_bus_write_config_word(slot->bus, slot->devfn, @@ -293,7 +256,6 @@ int cpci_led_off(struct slot* slot) return -ENODEV; } if(hs_csr & HS_CSR_LOO) { - /* Clear LOO */ hs_csr &= ~HS_CSR_LOO; if(pci_bus_write_config_word(slot->bus, slot->devfn, @@ -312,257 +274,23 @@ int cpci_led_off(struct slot* slot) * Device configuration functions */ -static int cpci_configure_dev(struct pci_bus *bus, struct pci_dev *dev) -{ - u8 irq_pin; - int r; - - dbg("%s - enter", __FUNCTION__); - - /* NOTE: device already setup from prior scan */ - - /* FIXME: How would we know if we need to enable the expansion ROM? */ - pci_write_config_word(dev, PCI_ROM_ADDRESS, 0x00L); - - /* Assign resources */ - dbg("assigning resources for %02x:%02x.%x", - dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - for (r = 0; r < 6; r++) { - struct resource *res = dev->resource + r; - if(res->flags) - pci_assign_resource(dev, r); - } - dbg("finished assigning resources for %02x:%02x.%x", - dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - - /* Does this function have an interrupt at all? */ - dbg("checking for function interrupt"); - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin); - if(irq_pin) { - dbg("function uses interrupt pin %d", irq_pin); - } - - /* - * Need to explicitly set irq field to 0 so that it'll get assigned - * by the pcibios platform dependent code called by pci_enable_device. - */ - dev->irq = 0; - - dbg("enabling device"); - pci_enable_device(dev); /* XXX check return */ - dbg("now dev->irq = %d", dev->irq); - if(irq_pin && dev->irq) { - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); - } - - /* Can't use pci_insert_device at the moment, do it manually for now */ - pci_proc_attach_device(dev); - dbg("notifying drivers"); - //pci_announce_device_to_drivers(dev); - dbg("%s - exit", __FUNCTION__); - return 0; -} - -static int cpci_configure_bridge(struct pci_bus* bus, struct pci_dev* dev) +static void cpci_enable_device(struct pci_dev *dev) { - int rc; - struct pci_bus* child; - struct resource* r; - u8 max, n; - u16 command; - - dbg("%s - enter", __FUNCTION__); + struct pci_bus *bus; - /* Do basic bridge initialization */ - rc = pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40); - if(rc) { - printk(KERN_ERR "%s - write of PCI_LATENCY_TIMER failed\n", __FUNCTION__); - } - rc = pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 0x40); - if(rc) { - printk(KERN_ERR "%s - write of PCI_SEC_LATENCY_TIMER failed\n", __FUNCTION__); - } - rc = pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / 4); - if(rc) { - printk(KERN_ERR "%s - write of PCI_CACHE_LINE_SIZE failed\n", __FUNCTION__); - } - - /* - * Set parent bridge's subordinate field so that configuration space - * access will work in pci_scan_bridge and friends. - */ - max = pci_max_busnr(); - bus->subordinate = max + 1; - pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, max + 1); - - /* Scan behind bridge */ - n = pci_scan_bridge(bus, dev, max, 2); - child = pci_find_bus(0, max + 1); - if (!child) - return -ENODEV; - pci_proc_attach_bus(child); - - /* - * Update parent bridge's subordinate field if there were more bridges - * behind the bridge that was scanned. - */ - if(n > max) { - bus->subordinate = n; - pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, n); - } - - /* - * Update the bridge resources of the bridge to accommodate devices - * behind it. - */ - pci_bus_size_bridges(child); - pci_bus_assign_resources(child); - - /* Enable resource mapping via command register */ - command = PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR; - r = child->resource[0]; - if(r && r->start) { - command |= PCI_COMMAND_IO; - } - r = child->resource[1]; - if(r && r->start) { - command |= PCI_COMMAND_MEMORY; - } - r = child->resource[2]; - if(r && r->start) { - command |= PCI_COMMAND_MEMORY; - } - rc = pci_write_config_word(dev, PCI_COMMAND, command); - if(rc) { - err("Error setting command register"); - return rc; - } - - /* Set bridge control register */ - command = PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_NO_ISA; - rc = pci_write_config_word(dev, PCI_BRIDGE_CONTROL, command); - if(rc) { - err("Error setting bridge control register"); - return rc; - } - dbg("%s - exit", __FUNCTION__); - return 0; -} - -static int configure_visit_pci_dev(struct pci_dev_wrapped *wrapped_dev, - struct pci_bus_wrapped *wrapped_bus) -{ - int rc; - struct pci_dev *dev = wrapped_dev->dev; - struct pci_bus *bus = wrapped_bus->bus; - struct slot* slot; - - dbg("%s - enter", __FUNCTION__); - - /* - * We need to fix up the hotplug representation with the Linux - * representation. - */ - if(wrapped_dev->data) { - slot = (struct slot*) wrapped_dev->data; - slot->dev = dev; - } - - /* If it's a bridge, scan behind it for devices */ + pci_enable_device(dev); if(dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - rc = cpci_configure_bridge(bus, dev); - if(rc) - return rc; - } - - /* Actually configure device */ - if(dev) { - rc = cpci_configure_dev(bus, dev); - if(rc) - return rc; - } - dbg("%s - exit", __FUNCTION__); - return 0; -} - -static int unconfigure_visit_pci_dev_phase2(struct pci_dev_wrapped *wrapped_dev, - struct pci_bus_wrapped *wrapped_bus) -{ - struct pci_dev *dev = wrapped_dev->dev; - struct slot* slot; - - dbg("%s - enter", __FUNCTION__); - if(!dev) - return -ENODEV; - - /* Remove the Linux representation */ - if(pci_remove_device_safe(dev)) { - err("Could not remove device\n"); - return -1; - } - - /* - * Now remove the hotplug representation. - */ - if(wrapped_dev->data) { - slot = (struct slot*) wrapped_dev->data; - slot->dev = NULL; - } else { - dbg("No hotplug representation for %02x:%02x.%x", - dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - } - dbg("%s - exit", __FUNCTION__); - return 0; -} - -static int unconfigure_visit_pci_bus_phase2(struct pci_bus_wrapped *wrapped_bus, - struct pci_dev_wrapped *wrapped_dev) -{ - struct pci_bus *bus = wrapped_bus->bus; - struct pci_bus *parent = bus->self->bus; - - dbg("%s - enter", __FUNCTION__); - - /* The cleanup code for proc entries regarding buses should be in the kernel... */ - if(bus->procdir) - dbg("detach_pci_bus %s", bus->procdir->name); - pci_proc_detach_bus(bus); - - /* The cleanup code should live in the kernel... */ - bus->self->subordinate = NULL; - - /* unlink from parent bus */ - list_del(&bus->node); - - /* Now, remove */ - if(bus) - kfree(bus); - - /* Update parent's subordinate field */ - if(parent) { - u8 n = pci_bus_max_busnr(parent); - if(n < parent->subordinate) { - parent->subordinate = n; - pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, n); + bus = dev->subordinate; + list_for_each_entry(dev, &bus->devices, bus_list) { + cpci_enable_device(dev); } } - dbg("%s - exit", __FUNCTION__); - return 0; } -static struct pci_visit configure_functions = { - .visit_pci_dev = configure_visit_pci_dev, -}; - -static struct pci_visit unconfigure_functions_phase2 = { - .post_visit_pci_bus = unconfigure_visit_pci_bus_phase2, - .post_visit_pci_dev = unconfigure_visit_pci_dev_phase2 -}; - - int cpci_configure_slot(struct slot* slot) { - int rc = 0; + unsigned char busnr; + struct pci_bus *child; dbg("%s - enter", __FUNCTION__); @@ -588,74 +316,44 @@ int cpci_configure_slot(struct slot* slot) slot->dev = pci_find_slot(slot->bus->number, slot->devfn); if(slot->dev == NULL) { err("Could not find PCI device for slot %02x", slot->number); - return 0; + return 1; } } - dbg("slot->dev = %p", slot->dev); - if(slot->dev) { - struct pci_dev *dev; - struct pci_dev_wrapped wrapped_dev; - struct pci_bus_wrapped wrapped_bus; - int i; - - memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped)); - memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped)); - - for (i = 0; i < 8; i++) { - dev = pci_find_slot(slot->bus->number, - PCI_DEVFN(PCI_SLOT(slot->dev->devfn), i)); - if(!dev) - continue; - wrapped_dev.dev = dev; - wrapped_bus.bus = slot->dev->bus; - if(i) - wrapped_dev.data = NULL; - else - wrapped_dev.data = (void*) slot; - rc = pci_visit_dev(&configure_functions, &wrapped_dev, &wrapped_bus); - } + + if (slot->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + pci_read_config_byte(slot->dev, PCI_SECONDARY_BUS, &busnr); + child = pci_add_new_bus(slot->dev->bus, slot->dev, busnr); + pci_do_scan_bus(child); + pci_bus_size_bridges(child); } - dbg("%s - exit, rc = %d", __FUNCTION__, rc); - return rc; + pci_bus_assign_resources(slot->dev->bus); + + cpci_enable_device(slot->dev); + + dbg("%s - exit", __FUNCTION__); + return 0; } int cpci_unconfigure_slot(struct slot* slot) { - int rc = 0; int i; - struct pci_dev_wrapped wrapped_dev; - struct pci_bus_wrapped wrapped_bus; struct pci_dev *dev; dbg("%s - enter", __FUNCTION__); - if(!slot->dev) { err("No device for slot %02x\n", slot->number); return -ENODEV; } - memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped)); - memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped)); - for (i = 0; i < 8; i++) { dev = pci_find_slot(slot->bus->number, PCI_DEVFN(PCI_SLOT(slot->devfn), i)); if(dev) { - wrapped_dev.dev = dev; - wrapped_bus.bus = dev->bus; - if(i) - wrapped_dev.data = NULL; - else - wrapped_dev.data = (void*) slot; - dbg("%s - unconfigure phase 2", __FUNCTION__); - rc = pci_visit_dev(&unconfigure_functions_phase2, - &wrapped_dev, - &wrapped_bus); - if(rc) - break; + pci_remove_bus_device(dev); + slot->dev = NULL; } } - dbg("%s - exit, rc = %d", __FUNCTION__, rc); - return rc; + dbg("%s - exit", __FUNCTION__); + return 0; } diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index f313121d514..46b294a1241 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -130,6 +130,7 @@ struct controller { u8 slot_bus; /* Bus where the slots handled by this controller sit */ u8 ctrlcap; u16 vendor_id; + u8 cap_base; }; struct irq_mapping { diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index ed1fd8d6178..df4915dbc32 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -607,7 +607,7 @@ static int pciehp_resume (struct pcie_device *dev) static struct pcie_port_service_id port_pci_ids[] = { { .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, - .port_type = PCIE_RC_PORT, + .port_type = PCIE_ANY_PORT, .service_type = PCIE_PORT_SERVICE_HP, .driver_data = 0, }, { /* end: all zeroes */ } diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 9e70c4681f7..1cda30bd6e4 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -109,20 +109,20 @@ enum ctrl_offsets { }; static int pcie_cap_base = 0; /* Base of the PCI Express capability item structure */ -#define PCIE_CAP_ID ( pcie_cap_base + PCIECAPID ) -#define NXT_CAP_PTR ( pcie_cap_base + NXTCAPPTR ) -#define CAP_REG ( pcie_cap_base + CAPREG ) -#define DEV_CAP ( pcie_cap_base + DEVCAP ) -#define DEV_CTRL ( pcie_cap_base + DEVCTRL ) -#define DEV_STATUS ( pcie_cap_base + DEVSTATUS ) -#define LNK_CAP ( pcie_cap_base + LNKCAP ) -#define LNK_CTRL ( pcie_cap_base + LNKCTRL ) -#define LNK_STATUS ( pcie_cap_base + LNKSTATUS ) -#define SLOT_CAP ( pcie_cap_base + SLOTCAP ) -#define SLOT_CTRL ( pcie_cap_base + SLOTCTRL ) -#define SLOT_STATUS ( pcie_cap_base + SLOTSTATUS ) -#define ROOT_CTRL ( pcie_cap_base + ROOTCTRL ) -#define ROOT_STATUS ( pcie_cap_base + ROOTSTATUS ) +#define PCIE_CAP_ID(cb) ( cb + PCIECAPID ) +#define NXT_CAP_PTR(cb) ( cb + NXTCAPPTR ) +#define CAP_REG(cb) ( cb + CAPREG ) +#define DEV_CAP(cb) ( cb + DEVCAP ) +#define DEV_CTRL(cb) ( cb + DEVCTRL ) +#define DEV_STATUS(cb) ( cb + DEVSTATUS ) +#define LNK_CAP(cb) ( cb + LNKCAP ) +#define LNK_CTRL(cb) ( cb + LNKCTRL ) +#define LNK_STATUS(cb) ( cb + LNKSTATUS ) +#define SLOT_CAP(cb) ( cb + SLOTCAP ) +#define SLOT_CTRL(cb) ( cb + SLOTCTRL ) +#define SLOT_STATUS(cb) ( cb + SLOTSTATUS ) +#define ROOT_CTRL(cb) ( cb + ROOTCTRL ) +#define ROOT_STATUS(cb) ( cb + ROOTSTATUS ) #define hp_register_read_word(pdev, reg , value) \ pci_read_config_word(pdev, reg, &value) @@ -303,7 +303,7 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd) return -1; } - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status); if (retval) { err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); return retval; @@ -317,7 +317,7 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd) } dbg("%s: Before hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, cmd); - retval = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL, cmd | CMD_CMPL_INTR_ENABLE); + retval = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), cmd | CMD_CMPL_INTR_ENABLE); if (retval) { err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); return retval; @@ -342,7 +342,7 @@ static int hpc_check_lnk_status(struct controller *ctrl) return -1; } - retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS, lnk_status); + retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(ctrl->cap_base), lnk_status); if (retval) { err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__); @@ -376,14 +376,14 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status) return -1; } - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); if (retval) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); return retval; } - dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__,SLOT_CTRL, slot_ctrl); + dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__,SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); atten_led_state = (slot_ctrl & ATTN_LED_CTRL) >> 6; @@ -423,13 +423,13 @@ static int hpc_get_power_status(struct slot * slot, u8 *status) return -1; } - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); if (retval) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); return retval; } - dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, slot_ctrl); + dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); pwr_state = (slot_ctrl & PWR_CTRL) >> 10; @@ -463,7 +463,7 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status) return -1; } - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status); if (retval) { err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); @@ -490,7 +490,7 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status) return -1; } - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status); if (retval) { err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); @@ -518,7 +518,7 @@ static int hpc_query_power_fault(struct slot * slot) return -1; } - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status); if (retval) { err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); @@ -549,7 +549,7 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) err("%s: Invalid HPC slot number!\n", __FUNCTION__); return -1; } - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); if (rc) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); @@ -574,7 +574,7 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) slot_cmd = slot_cmd | HP_INTR_ENABLE; pcie_write_cmd(slot, slot_cmd); - dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL, slot_cmd); + dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); return rc; } @@ -598,7 +598,7 @@ static void hpc_set_green_led_on(struct slot *slot) return ; } - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); if (rc) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); @@ -611,7 +611,7 @@ static void hpc_set_green_led_on(struct slot *slot) pcie_write_cmd(slot, slot_cmd); - dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, slot_cmd); + dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); return; } @@ -633,7 +633,7 @@ static void hpc_set_green_led_off(struct slot *slot) return ; } - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); if (rc) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); @@ -646,7 +646,7 @@ static void hpc_set_green_led_off(struct slot *slot) if (!pciehp_poll_mode) slot_cmd = slot_cmd | HP_INTR_ENABLE; pcie_write_cmd(slot, slot_cmd); - dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL, slot_cmd); + dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); return; } @@ -669,7 +669,7 @@ static void hpc_set_green_led_blink(struct slot *slot) return ; } - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); if (rc) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); @@ -683,7 +683,7 @@ static void hpc_set_green_led_blink(struct slot *slot) slot_cmd = slot_cmd | HP_INTR_ENABLE; pcie_write_cmd(slot, slot_cmd); - dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, slot_cmd); + dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); return; } @@ -707,7 +707,7 @@ int pcie_get_ctlr_slot_config(struct controller *ctrl, *first_device_num = 0; *num_ctlr_slots = 1; - rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP, slot_cap); + rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap); if (rc) { err("%s : hp_register_read_dword SLOT_CAP failed\n", __FUNCTION__); @@ -793,13 +793,13 @@ static int hpc_power_on_slot(struct slot * slot) return -1; } - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); if (retval) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); return retval; } - dbg("%s: SLOT_CTRL %x, value read %xn", __FUNCTION__, SLOT_CTRL, + dbg("%s: SLOT_CTRL %x, value read %xn", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_ON; @@ -813,7 +813,7 @@ static int hpc_power_on_slot(struct slot * slot) err("%s: Write %x command failed!\n", __FUNCTION__, slot_cmd); return -1; } - dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, slot_cmd); + dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); DBG_LEAVE_ROUTINE @@ -842,13 +842,13 @@ static int hpc_power_off_slot(struct slot * slot) err("%s: Invalid HPC slot number!\n", __FUNCTION__); return -1; } - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); if (retval) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); return retval; } - dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__, SLOT_CTRL, + dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_OFF; @@ -862,7 +862,7 @@ static int hpc_power_off_slot(struct slot * slot) err("%s: Write command failed!\n", __FUNCTION__); return -1; } - dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, slot_cmd); + dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); DBG_LEAVE_ROUTINE @@ -900,7 +900,7 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs) return IRQ_NONE; } - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); if (rc) { err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); return IRQ_NONE; @@ -918,7 +918,7 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs) dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc); /* Mask Hot-plug Interrupt Enable */ if (!pciehp_poll_mode) { - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); return IRQ_NONE; @@ -928,14 +928,14 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs) dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00; - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word); + rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); return IRQ_NONE; } dbg("%s: hp_register_write_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); if (rc) { err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); return IRQ_NONE; @@ -944,7 +944,7 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs) /* Clear command complete interrupt caused by this write */ temp_word = 0x1f; - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word); + rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); return IRQ_NONE; @@ -975,14 +975,14 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs) /* Clear all events after serving them */ temp_word = 0x1F; - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word); + rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); return IRQ_NONE; } /* Unmask Hot-plug Interrupt Enable */ if (!pciehp_poll_mode) { - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); return IRQ_NONE; @@ -992,14 +992,14 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs) dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word); + rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); return IRQ_NONE; } dbg("%s: hp_register_write_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); if (rc) { err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); return IRQ_NONE; @@ -1008,7 +1008,7 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs) /* Clear command complete interrupt caused by this write */ temp_word = 0x1F; - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word); + rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); return IRQ_NONE; @@ -1038,7 +1038,7 @@ static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value) return -1; } - retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP, lnk_cap); + retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap); if (retval) { err("%s : hp_register_read_dword LNK_CAP failed\n", __FUNCTION__); @@ -1079,7 +1079,7 @@ static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value return -1; } - retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP, lnk_cap); + retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap); if (retval) { err("%s : hp_register_read_dword LNK_CAP failed\n", __FUNCTION__); @@ -1141,7 +1141,7 @@ static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value) return -1; } - retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS, lnk_status); + retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status); if (retval) { err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__); @@ -1182,7 +1182,7 @@ static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value return -1; } - retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS, lnk_status); + retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status); if (retval) { err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__); @@ -1292,47 +1292,48 @@ int pcie_init(struct controller * ctrl, goto abort_free_ctlr; } - pcie_cap_base = cap_base; + ctrl->cap_base = cap_base; dbg("%s: pcie_cap_base %x\n", __FUNCTION__, pcie_cap_base); - rc = hp_register_read_word(pdev, CAP_REG, cap_reg); + rc = hp_register_read_word(pdev, CAP_REG(ctrl->cap_base), cap_reg); if (rc) { err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: CAP_REG offset %x cap_reg %x\n", __FUNCTION__, CAP_REG, cap_reg); + dbg("%s: CAP_REG offset %x cap_reg %x\n", __FUNCTION__, CAP_REG(ctrl->cap_base), cap_reg); - if (((cap_reg & SLOT_IMPL) == 0) || ((cap_reg & DEV_PORT_TYPE) != 0x0040)){ + if (((cap_reg & SLOT_IMPL) == 0) || (((cap_reg & DEV_PORT_TYPE) != 0x0040) + && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) { dbg("%s : This is not a root port or the port is not connected to a slot\n", __FUNCTION__); goto abort_free_ctlr; } - rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP, slot_cap); + rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap); if (rc) { err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: SLOT_CAP offset %x slot_cap %x\n", __FUNCTION__, SLOT_CAP, slot_cap); + dbg("%s: SLOT_CAP offset %x slot_cap %x\n", __FUNCTION__, SLOT_CAP(ctrl->cap_base), slot_cap); if (!(slot_cap & HP_CAP)) { dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__); goto abort_free_ctlr; } /* For debugging purpose */ - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); if (rc) { err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: SLOT_STATUS offset %x slot_status %x\n", __FUNCTION__, SLOT_STATUS, slot_status); + dbg("%s: SLOT_STATUS offset %x slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), slot_status); - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), slot_ctrl); if (rc) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: SLOT_CTRL offset %x slot_ctrl %x\n", __FUNCTION__, SLOT_CTRL, slot_ctrl); + dbg("%s: SLOT_CTRL offset %x slot_ctrl %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), slot_ctrl); if (first) { spin_lock_init(&hpc_event_lock); @@ -1372,36 +1373,37 @@ int pcie_init(struct controller * ctrl, php_ctlr->num_slots = 1; /* Mask Hot-plug Interrupt Enable */ - rc = hp_register_read_word(pdev, SLOT_CTRL, temp_word); + rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, temp_word); + dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), temp_word); temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00; - rc = hp_register_write_word(pdev, SLOT_CTRL, temp_word); + rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); goto abort_free_ctlr; } dbg("%s : Mask HPIE hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, temp_word); - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); if (rc) { err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: Mask HPIE SLOT_STATUS offset %x reads slot_status %x\n", __FUNCTION__, SLOT_STATUS, slot_status); + dbg("%s: Mask HPIE SLOT_STATUS offset %x reads slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base) + , slot_status); temp_word = 0x1F; /* Clear all events */ - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word); + rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS, temp_word); + dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), temp_word); if (pciehp_poll_mode) {/* Install interrupt polling code */ /* Install and start the interrupt polling timer */ @@ -1417,12 +1419,12 @@ int pcie_init(struct controller * ctrl, } } - rc = hp_register_read_word(pdev, SLOT_CTRL, temp_word); + rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, temp_word); + dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), temp_word); dbg("%s: slot_cap %x\n", __FUNCTION__, slot_cap); intr_enable = intr_enable | PRSN_DETECT_ENABLE; @@ -1446,27 +1448,27 @@ int pcie_init(struct controller * ctrl, dbg("%s: temp_word %x\n", __FUNCTION__, temp_word); /* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */ - rc = hp_register_write_word(pdev, SLOT_CTRL, temp_word); + rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); goto abort_free_ctlr; } dbg("%s : Unmask HPIE hp_register_write_word SLOT_CTRL with %x\n", __FUNCTION__, temp_word); - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); if (rc) { err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); goto abort_free_ctlr; } dbg("%s: Unmask HPIE SLOT_STATUS offset %x reads slot_status %x\n", __FUNCTION__, - SLOT_STATUS, slot_status); + SLOT_STATUS(ctrl->cap_base), slot_status); temp_word = 0x1F; /* Clear all events */ - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word); + rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); if (rc) { err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS, temp_word); + dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), temp_word); /* Add this HPC instance into the HPC list */ spin_lock(&list_lock); diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index f0c53f850ae..a70a5c5705f 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -95,7 +95,7 @@ static struct hotplug_slot_ops shpchp_hotplug_slot_ops = { */ static void release_slot(struct hotplug_slot *hotplug_slot) { - struct slot *slot = (struct slot *)hotplug_slot->private; + struct slot *slot = hotplug_slot->private; dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 9f90eb8e6ec..490a9553a06 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -1885,7 +1885,7 @@ int shpchp_enable_slot (struct slot *p_slot) func = shpchp_slot_find(p_slot->bus, p_slot->device, 0); if (!func) { dbg("%s: Error! slot NULL\n", __FUNCTION__); - return 1; + return -ENODEV; } /* Check to see if (latch closed, card present, power off) */ @@ -1894,19 +1894,19 @@ int shpchp_enable_slot (struct slot *p_slot) if (rc || !getstatus) { info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return 1; + return -ENODEV; } rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return 1; + return -ENODEV; } rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return 1; + return -ENODEV; } up(&p_slot->ctrl->crit_sect); @@ -1914,7 +1914,7 @@ int shpchp_enable_slot (struct slot *p_slot) func = shpchp_slot_create(p_slot->bus); if (func == NULL) - return 1; + return -ENOMEM; func->bus = p_slot->bus; func->device = p_slot->device; @@ -1939,7 +1939,7 @@ int shpchp_enable_slot (struct slot *p_slot) /* Setup slot structure with entry for empty slot */ func = shpchp_slot_create(p_slot->bus); if (func == NULL) - return (1); /* Out of memory */ + return -ENOMEM; /* Out of memory */ func->bus = p_slot->bus; func->device = p_slot->device; @@ -1972,7 +1972,7 @@ int shpchp_disable_slot (struct slot *p_slot) struct pci_func *func; if (!p_slot->ctrl) - return 1; + return -ENODEV; pci_bus = p_slot->ctrl->pci_dev->subordinate; @@ -1983,19 +1983,19 @@ int shpchp_disable_slot (struct slot *p_slot) if (ret || !getstatus) { info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return 1; + return -ENODEV; } ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (ret || getstatus) { info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return 1; + return -ENODEV; } ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (ret || !getstatus) { info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); - return 1; + return -ENODEV; } up(&p_slot->ctrl->crit_sect); @@ -2011,7 +2011,7 @@ int shpchp_disable_slot (struct slot *p_slot) /* Check the Class Code */ rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); if (rc) - return rc; + return -ENODEV; if (class_code == PCI_BASE_CLASS_DISPLAY) { /* Display/Video adapter (not supported) */ @@ -2020,13 +2020,13 @@ int shpchp_disable_slot (struct slot *p_slot) /* See if it's a bridge */ rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); if (rc) - return rc; + return -ENODEV; /* If it's a bridge, check the VGA Enable bit */ if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR); if (rc) - return rc; + return -ENODEV; /* If the VGA Enable bit is set, remove isn't supported */ if (BCR & PCI_BRIDGE_CTL_VGA) { @@ -2042,12 +2042,12 @@ int shpchp_disable_slot (struct slot *p_slot) if ((func != NULL) && !rc) { rc = remove_board(func, p_slot->ctrl); } else if (!rc) - rc = 1; + rc = -ENODEV; if (p_slot) update_slot_info(p_slot); - return(rc); + return rc; } diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 8568b207f18..6ca0061137a 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -73,6 +73,17 @@ resource_show(struct device * dev, char * buf) return (str - buf); } +static ssize_t modalias_show(struct device *dev, char *buf) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + + return sprintf(buf, "pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x\n", + pci_dev->vendor, pci_dev->device, + pci_dev->subsystem_vendor, pci_dev->subsystem_device, + (u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8), + (u8)(pci_dev->class)); +} + struct device_attribute pci_dev_attrs[] = { __ATTR_RO(resource), __ATTR_RO(vendor), @@ -82,6 +93,7 @@ struct device_attribute pci_dev_attrs[] = { __ATTR_RO(class), __ATTR_RO(irq), __ATTR_RO(local_cpus), + __ATTR_RO(modalias), __ATTR_NULL, }; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 79cdc16c52c..744da0d4ae5 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -32,33 +32,6 @@ extern unsigned char pci_max_busnr(void); extern unsigned char pci_bus_max_busnr(struct pci_bus *bus); extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap); -struct pci_dev_wrapped { - struct pci_dev *dev; - void *data; -}; - -struct pci_bus_wrapped { - struct pci_bus *bus; - void *data; -}; - -struct pci_visit { - int (* pre_visit_pci_bus) (struct pci_bus_wrapped *, - struct pci_dev_wrapped *); - int (* post_visit_pci_bus) (struct pci_bus_wrapped *, - struct pci_dev_wrapped *); - - int (* pre_visit_pci_dev) (struct pci_dev_wrapped *, - struct pci_bus_wrapped *); - int (* visit_pci_dev) (struct pci_dev_wrapped *, - struct pci_bus_wrapped *); - int (* post_visit_pci_dev) (struct pci_dev_wrapped *, - struct pci_bus_wrapped *); -}; - -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 */ diff --git a/drivers/pci/pcie/portdrv_bus.c b/drivers/pci/pcie/portdrv_bus.c index 4037a3e568d..3e84b501e6a 100644 --- a/drivers/pci/pcie/portdrv_bus.c +++ b/drivers/pci/pcie/portdrv_bus.c @@ -39,7 +39,8 @@ static int pcie_port_bus_match(struct device *dev, struct device_driver *drv) 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->port_type != PCIE_ANY_PORT && + driver->id_table->port_type != pciedev->id.port_type) || driver->id_table->service_type != pciedev->id.service_type ) return 0; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 026aa04669a..637e9493034 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -18,6 +18,7 @@ #include <linux/pci.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/acpi.h> #include "pci.h" /* Deal with broken BIOS'es that neglect to enable passive release, @@ -467,9 +468,6 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_APIC, * non-x86 architectures (yes Via exists on PPC among other places), * we must mask the PCI_INTERRUPT_LINE value versus 0xf to get * interrupts delivered properly. - * - * TODO: When we have device-specific interrupt routers, - * quirk_via_irqpic will go away from quirks. */ /* @@ -494,6 +492,29 @@ static void __devinit quirk_via_acpi(struct pci_dev *d) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_acpi ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_acpi ); +static void quirk_via_irqpic(struct pci_dev *dev) +{ + u8 irq, new_irq; + +#ifdef CONFIG_X86_IO_APIC + if (nr_ioapics && !skip_ioapic_setup) + return; +#endif +#ifdef CONFIG_ACPI + if (acpi_irq_model != ACPI_IRQ_MODEL_PIC) + return; +#endif + new_irq = dev->irq & 0xf; + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); + if (new_irq != irq) { + printk(KERN_INFO "PCI: Via PIC IRQ fixup for %s, from %d to %d\n", + pci_name(dev), irq, new_irq); + udelay(15); /* unknown if delay really needed */ + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq); + } +} +DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irqpic); + /* * PIIX3 USB: We have to disable USB interrupts that are * hardwired to PIRQD# and may be shared with an @@ -683,19 +704,6 @@ static void __init quirk_disable_pxb(struct pci_dev *pdev) } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb ); -/* - * VIA northbridges care about PCI_INTERRUPT_LINE - */ -int via_interrupt_line_quirk; - -static void __devinit quirk_via_bridge(struct pci_dev *pdev) -{ - if(pdev->devfn == 0) { - printk(KERN_INFO "PCI: Via IRQ fixup\n"); - via_interrupt_line_quirk = 1; - } -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_bridge ); /* * Serverworks CSB5 IDE does not fully support native mode |