diff options
Diffstat (limited to 'drivers/pci')
26 files changed, 545 insertions, 954 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..30af105271a 100644 --- a/drivers/pci/hotplug/cpci_hotplug_core.c +++ b/drivers/pci/hotplug/cpci_hotplug_core.c @@ -1,7 +1,7 @@ /* * CompactPCI Hot Plug Driver * - * Copyright (C) 2002 SOMA Networks, Inc. + * Copyright (C) 2002,2005 SOMA Networks, Inc. * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2001 IBM Corp. * @@ -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" @@ -45,18 +45,19 @@ #define dbg(format, arg...) \ do { \ - if(cpci_debug) \ + if (cpci_debug) \ printk (KERN_DEBUG "%s: " format "\n", \ MY_NAME , ## arg); \ - } while(0) + } while (0) #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) #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 @@ -106,10 +111,8 @@ enable_slot(struct hotplug_slot *hotplug_slot) dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); - if(controller->ops->set_power) { + if (controller->ops->set_power) retval = controller->ops->set_power(slot, 1); - } - return retval; } @@ -121,35 +124,41 @@ disable_slot(struct hotplug_slot *hotplug_slot) dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + down_write(&list_rwsem); + /* Unconfigure device */ dbg("%s - unconfiguring slot %s", __FUNCTION__, slot->hotplug_slot->name); - if((retval = cpci_unconfigure_slot(slot))) { + if ((retval = cpci_unconfigure_slot(slot))) { err("%s - could not unconfigure slot %s", __FUNCTION__, slot->hotplug_slot->name); - return retval; + goto disable_error; } dbg("%s - finished unconfiguring slot %s", __FUNCTION__, slot->hotplug_slot->name); /* Clear EXT (by setting it) */ - if(cpci_clear_ext(slot)) { + if (cpci_clear_ext(slot)) { err("%s - could not clear EXT for slot %s", __FUNCTION__, slot->hotplug_slot->name); retval = -ENODEV; + goto disable_error; } cpci_led_on(slot); - if(controller->ops->set_power) { - retval = controller->ops->set_power(slot, 0); - } + if (controller->ops->set_power) + if ((retval = controller->ops->set_power(slot, 0))) + goto disable_error; - if(update_adapter_status(slot->hotplug_slot, 0)) { + if (update_adapter_status(slot->hotplug_slot, 0)) warn("failure to update adapter file"); - } - - slot->extracting = 0; + if (slot->extracting) { + slot->extracting = 0; + atomic_dec(&extracting); + } +disable_error: + up_write(&list_rwsem); return retval; } @@ -158,9 +167,8 @@ cpci_get_power_status(struct slot *slot) { u8 power = 1; - if(controller->ops->get_power) { + if (controller->ops->get_power) power = controller->ops->get_power(slot); - } return power; } @@ -188,6 +196,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; @@ -195,6 +217,8 @@ static void release_slot(struct hotplug_slot *hotplug_slot) kfree(slot->hotplug_slot->info); kfree(slot->hotplug_slot->name); kfree(slot->hotplug_slot); + if (slot->dev) + pci_dev_put(slot->dev); kfree(slot); } @@ -216,9 +240,8 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) int status = -ENOMEM; int i; - if(!(controller && bus)) { + if (!(controller && bus)) return -ENODEV; - } /* * Create a structure for each slot, and register that slot @@ -273,10 +296,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: @@ -295,32 +318,30 @@ int cpci_hp_unregister_bus(struct pci_bus *bus) { struct slot *slot; - struct list_head *tmp; - struct list_head *next; - int status; + struct slot *tmp; + int status = 0; - spin_lock(&list_lock); - if(!slots) { - spin_unlock(&list_lock); + down_write(&list_rwsem); + if (!slots) { + up_write(&list_rwsem); return -1; } - list_for_each_safe(tmp, next, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - if(slot->bus == bus) { + list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) { + if (slot->bus == bus) { + list_del(&slot->slot_list); + slots--; + dbg("deregistering slot %s", slot->hotplug_slot->name); status = pci_hp_deregister(slot->hotplug_slot); - if(status) { + if (status) { err("pci_hp_deregister failed with error %d", status); - return status; + break; } - - list_del(&slot->slot_list); - slots--; } } - spin_unlock(&list_lock); - return 0; + up_write(&list_rwsem); + return status; } /* This is the interrupt mode interrupt handler */ @@ -330,7 +351,7 @@ cpci_hp_intr(int irq, void *data, struct pt_regs *regs) dbg("entered cpci_hp_intr"); /* Check to see if it was our interrupt */ - if((controller->irq_flags & SA_SHIRQ) && + if ((controller->irq_flags & SA_SHIRQ) && !controller->ops->check_irq(controller->dev_id)) { dbg("exited cpci_hp_intr, not our interrupt"); return IRQ_NONE; @@ -347,46 +368,38 @@ 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. */ static int -init_slots(void) +init_slots(int clear_ins) { struct slot *slot; - struct list_head *tmp; struct pci_dev* dev; dbg("%s - enter", __FUNCTION__); - spin_lock(&list_lock); - if(!slots) { - spin_unlock(&list_lock); + down_read(&list_rwsem); + if (!slots) { + up_read(&list_rwsem); return -1; } - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); + list_for_each_entry(slot, &slot_list, slot_list) { dbg("%s - looking at slot %s", __FUNCTION__, slot->hotplug_slot->name); - if(cpci_check_and_clear_ins(slot)) { + if (clear_ins && cpci_check_and_clear_ins(slot)) dbg("%s - cleared INS for slot %s", __FUNCTION__, slot->hotplug_slot->name); - dev = pci_find_slot(slot->bus->number, PCI_DEVFN(slot->number, 0)); - if(dev) { - if(update_adapter_status(slot->hotplug_slot, 1)) { - warn("failure to update adapter file"); - } - if(update_latch_status(slot->hotplug_slot, 1)) { - warn("failure to update latch file"); - } - slot->dev = dev; - } else { - err("%s - no driver attached to device in slot %s", - __FUNCTION__, slot->hotplug_slot->name); - } + dev = pci_get_slot(slot->bus, PCI_DEVFN(slot->number, 0)); + if (dev) { + if (update_adapter_status(slot->hotplug_slot, 1)) + warn("failure to update adapter file"); + if (update_latch_status(slot->hotplug_slot, 1)) + warn("failure to update latch file"); + slot->dev = dev; } } - spin_unlock(&list_lock); + up_read(&list_rwsem); dbg("%s - exit", __FUNCTION__); return 0; } @@ -395,27 +408,28 @@ static int check_slots(void) { struct slot *slot; - struct list_head *tmp; int extracted; int inserted; + u16 hs_csr; - spin_lock(&list_lock); - if(!slots) { - spin_unlock(&list_lock); + down_read(&list_rwsem); + if (!slots) { + up_read(&list_rwsem); err("no slots registered, shutting down"); return -1; } extracted = inserted = 0; - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); + list_for_each_entry(slot, &slot_list, slot_list) { 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); + if (cpci_check_and_clear_ins(slot)) { + /* + * Some broken hardware (e.g. PLX 9054AB) asserts + * ENUM# twice... + */ + if (slot->dev) { + warn("slot %s already inserted", + slot->hotplug_slot->name); inserted++; continue; } @@ -432,7 +446,7 @@ check_slots(void) /* Configure device */ dbg("%s - configuring slot %s", __FUNCTION__, slot->hotplug_slot->name); - if(cpci_configure_slot(slot)) { + if (cpci_configure_slot(slot)) { err("%s - could not configure slot %s", __FUNCTION__, slot->hotplug_slot->name); continue; @@ -445,13 +459,11 @@ check_slots(void) dbg("%s - slot %s HS_CSR (2) = %04x", __FUNCTION__, slot->hotplug_slot->name, hs_csr); - if(update_latch_status(slot->hotplug_slot, 1)) { + if (update_latch_status(slot->hotplug_slot, 1)) warn("failure to update latch file"); - } - if(update_adapter_status(slot->hotplug_slot, 1)) { + if (update_adapter_status(slot->hotplug_slot, 1)) warn("failure to update adapter file"); - } cpci_led_off(slot); @@ -461,9 +473,7 @@ check_slots(void) __FUNCTION__, slot->hotplug_slot->name, hs_csr); inserted++; - } else if(cpci_check_ext(slot)) { - u16 hs_csr; - + } else if (cpci_check_ext(slot)) { /* Process extraction request */ dbg("%s - slot %s extracted", __FUNCTION__, slot->hotplug_slot->name); @@ -473,23 +483,40 @@ check_slots(void) dbg("%s - slot %s HS_CSR = %04x", __FUNCTION__, slot->hotplug_slot->name, hs_csr); - if(!slot->extracting) { - if(update_latch_status(slot->hotplug_slot, 0)) { + if (!slot->extracting) { + if (update_latch_status(slot->hotplug_slot, 0)) { warn("failure to update latch file"); } slot->extracting = 1; + atomic_inc(&extracting); } 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); - if(inserted || extracted) { + 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,54 +524,37 @@ static int event_thread(void *data) { int rc; - struct slot *slot; - struct list_head *tmp; lock_kernel(); daemonize("cpci_hp_eventd"); unlock_kernel(); dbg("%s - event thread started", __FUNCTION__); - while(1) { + while (1) { dbg("event thread sleeping"); down_interruptible(&event_semaphore); dbg("event thread woken, thread_finished = %d", thread_finished); - if(thread_finished || signal_pending(current)) + 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) && !thread_finished); + if (thread_finished) + break; /* 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,45 +565,27 @@ static int poll_thread(void *data) { int rc; - struct slot *slot; - struct list_head *tmp; lock_kernel(); daemonize("cpci_hp_polld"); unlock_kernel(); - while(1) { - if(thread_finished || signal_pending(current)) + 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) && !thread_finished); } - msleep(100); } dbg("poll thread signals exit"); @@ -611,12 +603,11 @@ cpci_start_thread(void) init_MUTEX_LOCKED(&thread_exit); thread_finished = 0; - if(controller->irq) { + if (controller->irq) pid = kernel_thread(event_thread, NULL, 0); - } else { + else pid = kernel_thread(poll_thread, NULL, 0); - } - if(pid < 0) { + if (pid < 0) { err("Can't start up our thread"); return -1; } @@ -629,9 +620,8 @@ cpci_stop_thread(void) { thread_finished = 1; dbg("thread finish command given"); - if(controller->irq) { + if (controller->irq) up(&event_semaphore); - } dbg("wait for thread to exit"); down(&thread_exit); } @@ -641,42 +631,67 @@ cpci_hp_register_controller(struct cpci_hp_controller *new_controller) { int status = 0; - if(!controller) { - controller = new_controller; - if(controller->irq) { - if(request_irq(controller->irq, - cpci_hp_intr, - controller->irq_flags, - MY_NAME, controller->dev_id)) { - err("Can't get irq %d for the hotplug cPCI controller", controller->irq); - status = -ENODEV; - } - dbg("%s - acquired controller irq %d", __FUNCTION__, - controller->irq); + if (controller) + return -1; + if (!(new_controller && new_controller->ops)) + return -EINVAL; + if (new_controller->irq) { + if (!(new_controller->ops->enable_irq && + new_controller->ops->disable_irq)) + status = -EINVAL; + if (request_irq(new_controller->irq, + cpci_hp_intr, + new_controller->irq_flags, + MY_NAME, + new_controller->dev_id)) { + err("Can't get irq %d for the hotplug cPCI controller", + new_controller->irq); + status = -ENODEV; } - } else { - err("cPCI hotplug controller already registered"); - status = -1; + dbg("%s - acquired controller irq %d", + __FUNCTION__, new_controller->irq); } + if (!status) + controller = new_controller; return status; } +static void +cleanup_slots(void) +{ + struct slot *slot; + struct slot *tmp; + + /* + * Unregister all of our slots with the pci_hotplug subsystem, + * and free up all memory that we had allocated. + */ + down_write(&list_rwsem); + if (!slots) + goto cleanup_null; + list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) { + list_del(&slot->slot_list); + pci_hp_deregister(slot->hotplug_slot); + } +cleanup_null: + up_write(&list_rwsem); + return; +} + int cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller) { int status = 0; - if(controller) { - if(!thread_finished) { + if (controller) { + if (!thread_finished) cpci_stop_thread(); - } - if(controller->irq) { + if (controller->irq) free_irq(controller->irq, controller->dev_id); - } controller = NULL; - } else { + cleanup_slots(); + } else status = -ENODEV; - } return status; } @@ -687,32 +702,28 @@ cpci_hp_start(void) int status; dbg("%s - enter", __FUNCTION__); - if(!controller) { + if (!controller) 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(); - if(status) { - return status; - } + status = init_slots(first); + if (first) first = 0; - } + if (status) + return status; status = cpci_start_thread(); - if(status) { + if (status) return status; - } dbg("%s - thread started", __FUNCTION__); - if(controller->irq) { + if (controller->irq) { /* Start enum interrupt processing */ dbg("%s - enabling irq", __FUNCTION__); controller->ops->enable_irq(); @@ -724,11 +735,9 @@ cpci_hp_start(void) int cpci_hp_stop(void) { - if(!controller) { + if (!controller) return -ENODEV; - } - - if(controller->irq) { + if (controller->irq) { /* Stop enum interrupt processing */ dbg("%s - disabling irq", __FUNCTION__); controller->ops->disable_irq(); @@ -737,41 +746,10 @@ cpci_hp_stop(void) return 0; } -static void __exit -cleanup_slots(void) -{ - struct list_head *tmp; - struct slot *slot; - - /* - * Unregister all of our slots with the pci_hotplug subsystem, - * and free up all memory that we had allocated. - */ - spin_lock(&list_lock); - if(!slots) { - goto null_cleanup; - } - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - list_del(&slot->slot_list); - pci_hp_deregister(slot->hotplug_slot); - kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); - kfree(slot->hotplug_slot); - kfree(slot); - } - null_cleanup: - spin_unlock(&list_lock); - return; -} - int __init cpci_hotplug_init(int debug) { - spin_lock_init(&list_lock); cpci_debug = debug; - - info(DRIVER_DESC " version: " DRIVER_VERSION); return 0; } @@ -781,7 +759,8 @@ cpci_hotplug_exit(void) /* * Clean everything up. */ - cleanup_slots(); + cpci_hp_stop(); + cpci_hp_unregister_controller(controller); } EXPORT_SYMBOL_GPL(cpci_hp_register_controller); diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c index 2e969616f29..225b5e551dd 100644 --- a/drivers/pci/hotplug/cpci_hotplug_pci.c +++ b/drivers/pci/hotplug/cpci_hotplug_pci.c @@ -1,7 +1,7 @@ /* * CompactPCI Hot Plug Driver PCI functions * - * Copyright (C) 2002 by SOMA Networks, Inc. + * Copyright (C) 2002,2005 by SOMA Networks, Inc. * * All rights reserved. * @@ -32,20 +32,16 @@ #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; #define dbg(format, arg...) \ do { \ - if(cpci_debug) \ + if (cpci_debug) \ printk (KERN_DEBUG "%s: " format "\n", \ MY_NAME , ## arg); \ - } while(0) + } while (0) #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) @@ -61,16 +57,15 @@ u8 cpci_get_attention_status(struct slot* slot) hs_cap = pci_bus_find_capability(slot->bus, slot->devfn, PCI_CAP_ID_CHSWP); - if(!hs_cap) { + if (!hs_cap) return 0; - } - if(pci_bus_read_config_word(slot->bus, + if (pci_bus_read_config_word(slot->bus, slot->devfn, hs_cap + 2, - &hs_csr)) { + &hs_csr)) return 0; - } + return hs_csr & 0x0008 ? 1 : 0; } @@ -82,27 +77,22 @@ int cpci_set_attention_status(struct slot* slot, int status) hs_cap = pci_bus_find_capability(slot->bus, slot->devfn, PCI_CAP_ID_CHSWP); - if(!hs_cap) { + if (!hs_cap) return 0; - } - - if(pci_bus_read_config_word(slot->bus, + if (pci_bus_read_config_word(slot->bus, slot->devfn, hs_cap + 2, - &hs_csr)) { + &hs_csr)) return 0; - } - if(status) { + if (status) hs_csr |= HS_CSR_LOO; - } else { + else hs_csr &= ~HS_CSR_LOO; - } - if(pci_bus_write_config_word(slot->bus, + if (pci_bus_write_config_word(slot->bus, slot->devfn, hs_cap + 2, - hs_csr)) { + hs_csr)) return 0; - } return 1; } @@ -114,51 +104,16 @@ u16 cpci_get_hs_csr(struct slot* slot) hs_cap = pci_bus_find_capability(slot->bus, slot->devfn, PCI_CAP_ID_CHSWP); - if(!hs_cap) { + if (!hs_cap) return 0xFFFF; - } - - if(pci_bus_read_config_word(slot->bus, + if (pci_bus_read_config_word(slot->bus, slot->devfn, hs_cap + 2, - &hs_csr)) { + &hs_csr)) return 0xFFFF; - } 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; @@ -168,24 +123,22 @@ int cpci_check_and_clear_ins(struct slot* slot) hs_cap = pci_bus_find_capability(slot->bus, slot->devfn, PCI_CAP_ID_CHSWP); - if(!hs_cap) { + if (!hs_cap) return 0; - } - if(pci_bus_read_config_word(slot->bus, + if (pci_bus_read_config_word(slot->bus, slot->devfn, hs_cap + 2, - &hs_csr)) { + &hs_csr)) return 0; - } - if(hs_csr & HS_CSR_INS) { + if (hs_csr & HS_CSR_INS) { /* Clear INS (by setting it) */ - if(pci_bus_write_config_word(slot->bus, + if (pci_bus_write_config_word(slot->bus, slot->devfn, hs_cap + 2, - hs_csr)) { + hs_csr)) ins = 0; - } - ins = 1; + else + ins = 1; } return ins; } @@ -199,18 +152,15 @@ int cpci_check_ext(struct slot* slot) hs_cap = pci_bus_find_capability(slot->bus, slot->devfn, PCI_CAP_ID_CHSWP); - if(!hs_cap) { + if (!hs_cap) return 0; - } - if(pci_bus_read_config_word(slot->bus, + if (pci_bus_read_config_word(slot->bus, slot->devfn, hs_cap + 2, - &hs_csr)) { + &hs_csr)) return 0; - } - if(hs_csr & HS_CSR_EXT) { + if (hs_csr & HS_CSR_EXT) ext = 1; - } return ext; } @@ -222,23 +172,20 @@ int cpci_clear_ext(struct slot* slot) hs_cap = pci_bus_find_capability(slot->bus, slot->devfn, PCI_CAP_ID_CHSWP); - if(!hs_cap) { + if (!hs_cap) return -ENODEV; - } - if(pci_bus_read_config_word(slot->bus, + if (pci_bus_read_config_word(slot->bus, slot->devfn, hs_cap + 2, - &hs_csr)) { + &hs_csr)) return -ENODEV; - } - if(hs_csr & HS_CSR_EXT) { + if (hs_csr & HS_CSR_EXT) { /* Clear EXT (by setting it) */ - if(pci_bus_write_config_word(slot->bus, + if (pci_bus_write_config_word(slot->bus, slot->devfn, hs_cap + 2, - hs_csr)) { + hs_csr)) return -ENODEV; - } } return 0; } @@ -251,19 +198,16 @@ int cpci_led_on(struct slot* slot) hs_cap = pci_bus_find_capability(slot->bus, slot->devfn, PCI_CAP_ID_CHSWP); - if(!hs_cap) { + if (!hs_cap) return -ENODEV; - } - if(pci_bus_read_config_word(slot->bus, + if (pci_bus_read_config_word(slot->bus, slot->devfn, hs_cap + 2, - &hs_csr)) { + &hs_csr)) return -ENODEV; - } - if((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) { - /* Set LOO */ + if ((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) { hs_csr |= HS_CSR_LOO; - if(pci_bus_write_config_word(slot->bus, + if (pci_bus_write_config_word(slot->bus, slot->devfn, hs_cap + 2, hs_csr)) { @@ -283,19 +227,16 @@ int cpci_led_off(struct slot* slot) hs_cap = pci_bus_find_capability(slot->bus, slot->devfn, PCI_CAP_ID_CHSWP); - if(!hs_cap) { + if (!hs_cap) return -ENODEV; - } - if(pci_bus_read_config_word(slot->bus, + if (pci_bus_read_config_word(slot->bus, slot->devfn, hs_cap + 2, - &hs_csr)) { + &hs_csr)) return -ENODEV; - } - if(hs_csr & HS_CSR_LOO) { - /* Clear LOO */ + if (hs_csr & HS_CSR_LOO) { hs_csr &= ~HS_CSR_LOO; - if(pci_bus_write_config_word(slot->bus, + if (pci_bus_write_config_word(slot->bus, slot->devfn, hs_cap + 2, hs_csr)) { @@ -312,268 +253,21 @@ 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) -{ - int rc; - struct pci_bus* child; - struct resource* r; - u8 max, n; - u16 command; - - dbg("%s - enter", __FUNCTION__); - - /* 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 */ - 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); - } - } - 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__); - if(slot->dev == NULL) { + if (slot->dev == NULL) { dbg("pci_dev null, finding %02x:%02x:%x", slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn)); - slot->dev = pci_find_slot(slot->bus->number, slot->devfn); + slot->dev = pci_get_slot(slot->bus, slot->devfn); } /* Still NULL? Well then scan for it! */ - if(slot->dev == NULL) { + if (slot->dev == NULL) { int n; dbg("pci_dev still null"); @@ -583,79 +277,50 @@ int cpci_configure_slot(struct slot* slot) */ n = pci_scan_slot(slot->bus, slot->devfn); dbg("%s: pci_scan_slot returned %d", __FUNCTION__, n); - if(n > 0) + if (n > 0) pci_bus_add_devices(slot->bus); - slot->dev = pci_find_slot(slot->bus->number, slot->devfn); - if(slot->dev == NULL) { + slot->dev = pci_get_slot(slot->bus, 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); + + 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) { + 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, + dev = pci_get_slot(slot->bus, 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; + if (dev) { + pci_remove_bus_device(dev); + pci_dev_put(dev); } } - dbg("%s - exit, rc = %d", __FUNCTION__, rc); - return rc; + pci_dev_put(slot->dev); + slot->dev = NULL; + + dbg("%s - exit", __FUNCTION__); + return 0; } diff --git a/drivers/pci/hotplug/ibmphp.h b/drivers/pci/hotplug/ibmphp.h index 5bc039da647..c22e0284d7b 100644 --- a/drivers/pci/hotplug/ibmphp.h +++ b/drivers/pci/hotplug/ibmphp.h @@ -196,7 +196,7 @@ struct ebda_hpc_bus { /******************************************************************** -* THREE TYPE OF HOT PLUG CONTROLER * +* THREE TYPE OF HOT PLUG CONTROLLER * ********************************************************************/ struct isa_ctlr_access { diff --git a/drivers/pci/hotplug/ibmphp_hpc.c b/drivers/pci/hotplug/ibmphp_hpc.c index 6894b548c8c..1a3eb8d3d4c 100644 --- a/drivers/pci/hotplug/ibmphp_hpc.c +++ b/drivers/pci/hotplug/ibmphp_hpc.c @@ -64,7 +64,7 @@ static int to_debug = FALSE; #define WPG_I2C_OR 0x2000 // I2C OR operation //---------------------------------------------------------------------------- -// Command set for I2C Master Operation Setup Regisetr +// Command set for I2C Master Operation Setup Register //---------------------------------------------------------------------------- #define WPG_READATADDR_MASK 0x00010000 // read,bytes,I2C shifted,index #define WPG_WRITEATADDR_MASK 0x40010000 // write,bytes,I2C shifted,index @@ -835,7 +835,7 @@ static void poll_hpc (void) if (ibmphp_shutdown) break; - /* try to get the lock to do some kind of harware access */ + /* try to get the lock to do some kind of hardware access */ down (&semOperations); switch (poll_state) { @@ -906,7 +906,7 @@ static void poll_hpc (void) poll_state = POLL_LATCH_REGISTER; break; } - /* give up the harware semaphore */ + /* give up the hardware semaphore */ up (&semOperations); /* sleep for a short time just for good measure */ msleep(100); diff --git a/drivers/pci/hotplug/ibmphp_pci.c b/drivers/pci/hotplug/ibmphp_pci.c index 2335fac65fb..8122fe734aa 100644 --- a/drivers/pci/hotplug/ibmphp_pci.c +++ b/drivers/pci/hotplug/ibmphp_pci.c @@ -1308,10 +1308,10 @@ static int unconfigure_boot_device (u8 busno, u8 device, u8 function) /* ????????? DO WE NEED TO WRITE ANYTHING INTO THE PCI CONFIG SPACE BACK ?????????? */ } else { /* This is Memory */ - start_address &= PCI_BASE_ADDRESS_MEM_MASK; if (start_address & PCI_BASE_ADDRESS_MEM_PREFETCH) { /* pfmem */ debug ("start address of pfmem is %x\n", start_address); + start_address &= PCI_BASE_ADDRESS_MEM_MASK; if (ibmphp_find_resource (bus, start_address, &pfmem, PFMEM) < 0) { err ("cannot find corresponding PFMEM resource to remove\n"); @@ -1325,6 +1325,8 @@ static int unconfigure_boot_device (u8 busno, u8 device, u8 function) } else { /* regular memory */ debug ("start address of mem is %x\n", start_address); + start_address &= PCI_BASE_ADDRESS_MEM_MASK; + if (ibmphp_find_resource (bus, start_address, &mem, MEM) < 0) { err ("cannot find corresponding MEM resource to remove\n"); return -EIO; @@ -1422,9 +1424,9 @@ static int unconfigure_boot_bridge (u8 busno, u8 device, u8 function) /* ????????? DO WE NEED TO WRITE ANYTHING INTO THE PCI CONFIG SPACE BACK ?????????? */ } else { /* This is Memory */ - start_address &= PCI_BASE_ADDRESS_MEM_MASK; if (start_address & PCI_BASE_ADDRESS_MEM_PREFETCH) { /* pfmem */ + start_address &= PCI_BASE_ADDRESS_MEM_MASK; if (ibmphp_find_resource (bus, start_address, &pfmem, PFMEM) < 0) { err ("cannot find corresponding PFMEM resource to remove\n"); return -EINVAL; @@ -1436,6 +1438,7 @@ static int unconfigure_boot_bridge (u8 busno, u8 device, u8 function) } } else { /* regular memory */ + start_address &= PCI_BASE_ADDRESS_MEM_MASK; if (ibmphp_find_resource (bus, start_address, &mem, MEM) < 0) { err ("cannot find corresponding MEM resource to remove\n"); return -EINVAL; diff --git a/drivers/pci/hotplug/pci_hotplug.h b/drivers/pci/hotplug/pci_hotplug.h index 57ace325168..88d44f7fef2 100644 --- a/drivers/pci/hotplug/pci_hotplug.h +++ b/drivers/pci/hotplug/pci_hotplug.h @@ -150,7 +150,7 @@ struct hotplug_slot_info { * @name: the name of the slot being registered. This string must * be unique amoung slots registered on this system. * @ops: pointer to the &struct hotplug_slot_ops to be used for this slot - * @info: pointer to the &struct hotplug_slot_info for the inital values for + * @info: pointer to the &struct hotplug_slot_info for the initial values for * this slot. * @release: called during pci_hp_deregister to free memory allocated in a * hotplug_slot structure. 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 72baf749e65..df4915dbc32 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -90,6 +90,22 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { .get_cur_bus_speed = get_cur_bus_speed, }; +/** + * release_slot - free up the memory used by a slot + * @hotplug_slot: slot to free + */ +static void release_slot(struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = hotplug_slot->private; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + kfree(slot->hotplug_slot->info); + kfree(slot->hotplug_slot->name); + kfree(slot->hotplug_slot); + kfree(slot); +} + static int init_slots(struct controller *ctrl) { struct slot *new_slot; @@ -139,7 +155,8 @@ static int init_slots(struct controller *ctrl) /* register this slot with the hotplug pci core */ new_slot->hotplug_slot->private = new_slot; - make_slot_name (new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot); + new_slot->hotplug_slot->release = &release_slot; + make_slot_name(new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot); new_slot->hotplug_slot->ops = &pciehp_hotplug_slot_ops; new_slot->hpc_ops->get_power_status(new_slot, &(new_slot->hotplug_slot->info->power_status)); @@ -188,10 +205,6 @@ static int cleanup_slots (struct controller * ctrl) while (old_slot) { next_slot = old_slot->next; pci_hp_deregister (old_slot->hotplug_slot); - kfree(old_slot->hotplug_slot->info); - kfree(old_slot->hotplug_slot->name); - kfree(old_slot->hotplug_slot); - kfree(old_slot); old_slot = next_slot; } @@ -594,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/pcihp_skeleton.c b/drivers/pci/hotplug/pcihp_skeleton.c index 6605d6bda52..3194d51c6ec 100644 --- a/drivers/pci/hotplug/pcihp_skeleton.c +++ b/drivers/pci/hotplug/pcihp_skeleton.c @@ -297,7 +297,7 @@ static int __init init_slots(void) hotplug_slot->ops = &skel_hotplug_slot_ops; /* - * Initilize the slot info structure with some known + * Initialize the slot info structure with some known * good values. */ info->power_status = get_power_status(slot); 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/hotplug/shpchprm_acpi.c b/drivers/pci/hotplug/shpchprm_acpi.c index 243a51d88b8..7957cdc72cd 100644 --- a/drivers/pci/hotplug/shpchprm_acpi.c +++ b/drivers/pci/hotplug/shpchprm_acpi.c @@ -1626,7 +1626,7 @@ int shpchprm_set_hpp( pci_bus->number = func->bus; devfn = PCI_DEVFN(func->device, func->function); - ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus); + ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->slot_bus); if (ab) { if (ab->_hpp) { @@ -1681,7 +1681,7 @@ void shpchprm_enable_card( | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; bcmd = bcommand = bcommand | PCI_BRIDGE_CTL_NO_ISA; - ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus); + ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->slot_bus); if (ab) { if (ab->_hpp) { if (ab->_hpp->enable_perr) { diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 22ecd3b058b..30206ac43c4 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -522,7 +522,7 @@ void pci_scan_msi_device(struct pci_dev *dev) * msi_capability_init - configure device's MSI capability structure * @dev: pointer to the pci_dev data structure of MSI device function * - * Setup the MSI capability structure of device funtion with a single + * Setup the MSI capability structure of device function with a single * MSI vector, regardless of device function is capable of handling * multiple messages. A return of zero indicates the successful setup * of an entry zero with the new MSI vector or non-zero for otherwise. @@ -599,7 +599,7 @@ static int msi_capability_init(struct pci_dev *dev) * msix_capability_init - configure device's MSI-X capability * @dev: pointer to the pci_dev data structure of MSI-X device function * - * Setup the MSI-X capability structure of device funtion with a + * Setup the MSI-X capability structure of device function with a * single MSI-X vector. A return of zero indicates the successful setup of * requested MSI-X entries with allocated vectors or non-zero for otherwise. **/ @@ -1074,7 +1074,7 @@ void pci_disable_msix(struct pci_dev* dev) * msi_remove_pci_irq_vectors - reclaim MSI(X) vectors to unused state * @dev: pointer to the pci_dev data structure of MSI(X) device function * - * Being called during hotplug remove, from which the device funciton + * Being called during hotplug remove, from which the device function * is hot-removed. All previous assigned MSI/MSI-X vectors, if * allocated for this device function, are reclaimed to unused state, * which may be used later on. diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 968eb32f292..bc01d34e263 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -19,7 +19,7 @@ static u32 ctrlset_buf[3] = {0, 0, 0}; static u32 global_ctrlsets = 0; -u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66}; +static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66}; static acpi_status acpi_query_osc ( diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 37b7961efc4..fe98553c978 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -318,6 +318,14 @@ static int pci_device_resume(struct device * dev) return 0; } +static void pci_device_shutdown(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + struct pci_driver *drv = pci_dev->driver; + + if (drv && drv->shutdown) + drv->shutdown(pci_dev); +} #define kobj_to_pci_driver(obj) container_of(obj, struct device_driver, kobj) #define attr_to_driver_attribute(obj) container_of(obj, struct driver_attribute, attr) @@ -373,7 +381,7 @@ pci_populate_driver_dir(struct pci_driver *drv) * * Adds the driver structure to the list of registered drivers. * Returns a negative value on error, otherwise 0. - * If no error occured, the driver remains registered even if + * If no error occurred, the driver remains registered even if * no device was claimed during registration. */ int pci_register_driver(struct pci_driver *drv) @@ -385,6 +393,7 @@ int pci_register_driver(struct pci_driver *drv) drv->driver.bus = &pci_bus_type; drv->driver.probe = pci_device_probe; drv->driver.remove = pci_device_remove; + drv->driver.shutdown = pci_device_shutdown, drv->driver.owner = drv->owner; drv->driver.kobj.ktype = &pci_driver_kobj_type; pci_init_dynids(&drv->dynids); diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index d57ae71d32b..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, }; @@ -91,6 +103,7 @@ pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count) struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj)); unsigned int size = 64; loff_t init_off = off; + u8 *data = (u8*) buf; /* Several chips lock up trying to read undefined config space */ if (capable(CAP_SYS_ADMIN)) { @@ -108,30 +121,47 @@ pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count) size = count; } - while (off & 3) { - unsigned char val; + if ((off & 1) && size) { + u8 val; pci_read_config_byte(dev, off, &val); - buf[off - init_off] = val; + data[off - init_off] = val; off++; - if (--size == 0) - break; + size--; + } + + if ((off & 3) && size > 2) { + u16 val; + pci_read_config_word(dev, off, &val); + data[off - init_off] = val & 0xff; + data[off - init_off + 1] = (val >> 8) & 0xff; + off += 2; + size -= 2; } while (size > 3) { - unsigned int val; + u32 val; pci_read_config_dword(dev, off, &val); - buf[off - init_off] = val & 0xff; - buf[off - init_off + 1] = (val >> 8) & 0xff; - buf[off - init_off + 2] = (val >> 16) & 0xff; - buf[off - init_off + 3] = (val >> 24) & 0xff; + data[off - init_off] = val & 0xff; + data[off - init_off + 1] = (val >> 8) & 0xff; + data[off - init_off + 2] = (val >> 16) & 0xff; + data[off - init_off + 3] = (val >> 24) & 0xff; off += 4; size -= 4; } - while (size > 0) { - unsigned char val; + if (size >= 2) { + u16 val; + pci_read_config_word(dev, off, &val); + data[off - init_off] = val & 0xff; + data[off - init_off + 1] = (val >> 8) & 0xff; + off += 2; + size -= 2; + } + + if (size > 0) { + u8 val; pci_read_config_byte(dev, off, &val); - buf[off - init_off] = val; + data[off - init_off] = val; off++; --size; } @@ -145,6 +175,7 @@ pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count) struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj)); unsigned int size = count; loff_t init_off = off; + u8 *data = (u8*) buf; if (off > dev->cfg_size) return 0; @@ -152,26 +183,41 @@ pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count) size = dev->cfg_size - off; count = size; } - - while (off & 3) { - pci_write_config_byte(dev, off, buf[off - init_off]); + + if ((off & 1) && size) { + pci_write_config_byte(dev, off, data[off - init_off]); off++; - if (--size == 0) - break; + size--; } + + if ((off & 3) && size > 2) { + u16 val = data[off - init_off]; + val |= (u16) data[off - init_off + 1] << 8; + pci_write_config_word(dev, off, val); + off += 2; + size -= 2; + } while (size > 3) { - unsigned int val = buf[off - init_off]; - val |= (unsigned int) buf[off - init_off + 1] << 8; - val |= (unsigned int) buf[off - init_off + 2] << 16; - val |= (unsigned int) buf[off - init_off + 3] << 24; + u32 val = data[off - init_off]; + val |= (u32) data[off - init_off + 1] << 8; + val |= (u32) data[off - init_off + 2] << 16; + val |= (u32) data[off - init_off + 3] << 24; pci_write_config_dword(dev, off, val); off += 4; size -= 4; } + + if (size >= 2) { + u16 val = data[off - init_off]; + val |= (u16) data[off - init_off + 1] << 8; + pci_write_config_word(dev, off, val); + off += 2; + size -= 2; + } - while (size > 0) { - pci_write_config_byte(dev, off, buf[off - init_off]); + if (size) { + pci_write_config_byte(dev, off, data[off - init_off]); off++; --size; } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index bfbff833526..f04b9ffe415 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -16,6 +16,7 @@ #include <linux/module.h> #include <linux/spinlock.h> #include <asm/dma.h> /* isa_dma_bridge_buggy */ +#include "pci.h" /** @@ -398,10 +399,10 @@ pci_enable_device(struct pci_dev *dev) { int err; - dev->is_enabled = 1; if ((err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1))) return err; pci_fixup_device(pci_fixup_enable, dev); + dev->is_enabled = 1; return 0; } @@ -427,16 +428,15 @@ pci_disable_device(struct pci_dev *dev) { u16 pci_command; - dev->is_enabled = 0; - dev->is_busmaster = 0; - pci_read_config_word(dev, PCI_COMMAND, &pci_command); if (pci_command & PCI_COMMAND_MASTER) { pci_command &= ~PCI_COMMAND_MASTER; pci_write_config_word(dev, PCI_COMMAND, pci_command); } + dev->is_busmaster = 0; pcibios_disable_device(dev); + dev->is_enabled = 0; } /** @@ -749,17 +749,6 @@ pci_set_dma_mask(struct pci_dev *dev, u64 mask) } int -pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask) -{ - if (!pci_dac_dma_supported(dev, mask)) - return -EIO; - - dev->dma_mask = mask; - - return 0; -} - -int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask) { if (!pci_dma_supported(dev, mask)) @@ -821,7 +810,6 @@ EXPORT_SYMBOL(pci_set_master); EXPORT_SYMBOL(pci_set_mwi); EXPORT_SYMBOL(pci_clear_mwi); EXPORT_SYMBOL(pci_set_dma_mask); -EXPORT_SYMBOL(pci_dac_set_dma_mask); EXPORT_SYMBOL(pci_set_consistent_dma_mask); EXPORT_SYMBOL(pci_assign_resource); EXPORT_SYMBOL(pci_find_parent_resource); 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/pci.ids b/drivers/pci/pci.ids index 93481b41b61..1d2ef1e2ffc 100644 --- a/drivers/pci/pci.ids +++ b/drivers/pci/pci.ids @@ -7173,6 +7173,7 @@ 080f Sentry5 DDR/SDR RAM Controller 0811 Sentry5 External Interface Core 0816 BCM3302 Sentry5 MIPS32 CPU + 1600 NetXtreme BCM5752 Gigabit Ethernet PCI Express 1644 NetXtreme BCM5700 Gigabit Ethernet 1014 0277 Broadcom Vigil B5700 1000Base-T 1028 00d1 Broadcom BCM5700 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/probe.c b/drivers/pci/probe.c index 6f0edadd132..fd48b201eb5 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -9,6 +9,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/cpumask.h> +#include "pci.h" #define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ #define CARDBUS_RESERVE_BUSNR 3 @@ -124,7 +125,7 @@ static inline unsigned int pci_calc_resource_flags(unsigned int flags) /* * Find the extent of a PCI decode.. */ -static u32 pci_size(u32 base, u32 maxbase, unsigned long mask) +static u32 pci_size(u32 base, u32 maxbase, u32 mask) { u32 size = mask & maxbase; /* Find the significant bits */ if (!size) diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 84cc4f620d8..e68bbfb1e7c 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -15,6 +15,7 @@ #include <asm/uaccess.h> #include <asm/byteorder.h> +#include "pci.h" static int proc_initialized; /* = 0 */ diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 15a39805168..968033fd29f 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -18,6 +18,8 @@ #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, which can cause problems in combination with the 82441FX/PPro MTRRs */ @@ -328,6 +330,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, quirk_ich4_lpc_acpi ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, quirk_ich4_lpc_acpi ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, quirk_ich4_lpc_acpi ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, quirk_ich4_lpc_acpi ); /* * VIA ACPI: One IO region pointed to by longword at @@ -453,24 +456,16 @@ static void __init quirk_amd_8131_ioapic(struct pci_dev *dev) } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_APIC, quirk_amd_8131_ioapic ); +static void __init quirk_svw_msi(struct pci_dev *dev) +{ + pci_msi_quirk = 1; + printk(KERN_WARNING "PCI: MSI quirk detected. pci_msi_quirk set.\n"); +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_svw_msi ); #endif /* CONFIG_X86_IO_APIC */ /* - * Via 686A/B: The PCI_INTERRUPT_LINE register for the on-chip - * devices, USB0/1, AC97, MC97, and ACPI, has an unusual feature: - * when written, it makes an internal connection to the PIC. - * For these devices, this register is defined to be 4 bits wide. - * Normally this is fine. However for IO-APIC motherboards, or - * 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. - */ - -/* * FIXME: it is questionable that quirk_via_acpi * is needed. It shows up as an ISA bridge, and does not * support the PCI_INTERRUPT_LINE register at all. Therefore @@ -493,6 +488,31 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vi DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_acpi ); /* + * Via 686A/B: The PCI_INTERRUPT_LINE register for the on-chip + * devices, USB0/1, AC97, MC97, and ACPI, has an unusual feature: + * when written, it makes an internal connection to the PIC. + * For these devices, this register is defined to be 4 bits wide. + * Normally this is fine. However for IO-APIC motherboards, or + * 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. + */ +static void quirk_via_irq(struct pci_dev *dev) +{ + u8 irq, new_irq; + + new_irq = dev->irq & 0xf; + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); + if (new_irq != irq) { + printk(KERN_INFO "PCI: Via 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_irq); + +/* * PIIX3 USB: We have to disable USB interrupts that are * hardwired to PIRQD# and may be shared with an * external device. @@ -681,19 +701,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 |