diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-05-27 21:47:59 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-05-27 21:47:59 -0400 |
| commit | 1ec7d99c16e69a9ed8ffeaa6c1846025b84bebad (patch) | |
| tree | c01a0eb7355cb00d6db27f222559cd8bbe7c7bb3 | |
| parent | 3dbfd0801bbbaf2800d7497d83d743a614430e82 (diff) | |
| parent | 9e4f2e8d4ddb04ad16a3828cd9a369a5a5287009 (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6:
pciehp: add message about pciehp_slot_with_bus option
pci hotplug core: add check of duplicate slot name
pciehp: move msleep after power off
pciehp: poll cmd completion if hotplug interrupt is disabled
pciehp: fix slow probing
pciehp: fix NULL dereference in interrupt handler
shpchp: add message about shpchp_slot_with_bus option
PCI: don't enable ASPM on devices with mixed PCIe/PCI functions
| -rw-r--r-- | drivers/pci/hotplug/pci_hotplug_core.c | 7 | ||||
| -rw-r--r-- | drivers/pci/hotplug/pciehp.h | 11 | ||||
| -rw-r--r-- | drivers/pci/hotplug/pciehp_core.c | 6 | ||||
| -rw-r--r-- | drivers/pci/hotplug/pciehp_ctrl.c | 36 | ||||
| -rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 129 | ||||
| -rw-r--r-- | drivers/pci/hotplug/shpchp_core.c | 4 | ||||
| -rw-r--r-- | drivers/pci/pcie/aspm.c | 20 |
7 files changed, 159 insertions, 54 deletions
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index 925ba16355ce..a11021e8ce37 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c | |||
| @@ -619,6 +619,7 @@ static struct hotplug_slot *get_slot_from_name (const char *name) | |||
| 619 | int pci_hp_register (struct hotplug_slot *slot) | 619 | int pci_hp_register (struct hotplug_slot *slot) |
| 620 | { | 620 | { |
| 621 | int result; | 621 | int result; |
| 622 | struct hotplug_slot *tmp; | ||
| 622 | 623 | ||
| 623 | if (slot == NULL) | 624 | if (slot == NULL) |
| 624 | return -ENODEV; | 625 | return -ENODEV; |
| @@ -630,7 +631,11 @@ int pci_hp_register (struct hotplug_slot *slot) | |||
| 630 | return -EINVAL; | 631 | return -EINVAL; |
| 631 | } | 632 | } |
| 632 | 633 | ||
| 633 | /* this can fail if we have already registered a slot with the same name */ | 634 | /* Check if we have already registered a slot with the same name. */ |
| 635 | tmp = get_slot_from_name(slot->name); | ||
| 636 | if (tmp) | ||
| 637 | return -EEXIST; | ||
| 638 | |||
| 634 | slot->kobj.kset = pci_hotplug_slots_kset; | 639 | slot->kobj.kset = pci_hotplug_slots_kset; |
| 635 | result = kobject_init_and_add(&slot->kobj, &hotplug_slot_ktype, NULL, | 640 | result = kobject_init_and_add(&slot->kobj, &hotplug_slot_ktype, NULL, |
| 636 | "%s", slot->name); | 641 | "%s", slot->name); |
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 8264a7680435..79c9ddaad3fb 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h | |||
| @@ -97,6 +97,7 @@ struct controller { | |||
| 97 | u8 cap_base; | 97 | u8 cap_base; |
| 98 | struct timer_list poll_timer; | 98 | struct timer_list poll_timer; |
| 99 | volatile int cmd_busy; | 99 | volatile int cmd_busy; |
| 100 | unsigned int no_cmd_complete:1; | ||
| 100 | }; | 101 | }; |
| 101 | 102 | ||
| 102 | #define INT_BUTTON_IGNORE 0 | 103 | #define INT_BUTTON_IGNORE 0 |
| @@ -135,6 +136,7 @@ struct controller { | |||
| 135 | #define PWR_LED_PRSN 0x00000010 | 136 | #define PWR_LED_PRSN 0x00000010 |
| 136 | #define HP_SUPR_RM_SUP 0x00000020 | 137 | #define HP_SUPR_RM_SUP 0x00000020 |
| 137 | #define EMI_PRSN 0x00020000 | 138 | #define EMI_PRSN 0x00020000 |
| 139 | #define NO_CMD_CMPL_SUP 0x00040000 | ||
| 138 | 140 | ||
| 139 | #define ATTN_BUTTN(ctrl) ((ctrl)->slot_cap & ATTN_BUTTN_PRSN) | 141 | #define ATTN_BUTTN(ctrl) ((ctrl)->slot_cap & ATTN_BUTTN_PRSN) |
| 140 | #define POWER_CTRL(ctrl) ((ctrl)->slot_cap & PWR_CTRL_PRSN) | 142 | #define POWER_CTRL(ctrl) ((ctrl)->slot_cap & PWR_CTRL_PRSN) |
| @@ -143,13 +145,14 @@ struct controller { | |||
| 143 | #define PWR_LED(ctrl) ((ctrl)->slot_cap & PWR_LED_PRSN) | 145 | #define PWR_LED(ctrl) ((ctrl)->slot_cap & PWR_LED_PRSN) |
| 144 | #define HP_SUPR_RM(ctrl) ((ctrl)->slot_cap & HP_SUPR_RM_SUP) | 146 | #define HP_SUPR_RM(ctrl) ((ctrl)->slot_cap & HP_SUPR_RM_SUP) |
| 145 | #define EMI(ctrl) ((ctrl)->slot_cap & EMI_PRSN) | 147 | #define EMI(ctrl) ((ctrl)->slot_cap & EMI_PRSN) |
| 148 | #define NO_CMD_CMPL(ctrl) ((ctrl)->slot_cap & NO_CMD_CMPL_SUP) | ||
| 146 | 149 | ||
| 147 | extern int pciehp_sysfs_enable_slot(struct slot *slot); | 150 | extern int pciehp_sysfs_enable_slot(struct slot *slot); |
| 148 | extern int pciehp_sysfs_disable_slot(struct slot *slot); | 151 | extern int pciehp_sysfs_disable_slot(struct slot *slot); |
| 149 | extern u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl); | 152 | extern u8 pciehp_handle_attention_button(struct slot *p_slot); |
| 150 | extern u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl); | 153 | extern u8 pciehp_handle_switch_change(struct slot *p_slot); |
| 151 | extern u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl); | 154 | extern u8 pciehp_handle_presence_change(struct slot *p_slot); |
| 152 | extern u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl); | 155 | extern u8 pciehp_handle_power_fault(struct slot *p_slot); |
| 153 | extern int pciehp_configure_device(struct slot *p_slot); | 156 | extern int pciehp_configure_device(struct slot *p_slot); |
| 154 | extern int pciehp_unconfigure_device(struct slot *p_slot); | 157 | extern int pciehp_unconfigure_device(struct slot *p_slot); |
| 155 | extern void pciehp_queue_pushbutton_work(struct work_struct *work); | 158 | extern void pciehp_queue_pushbutton_work(struct work_struct *work); |
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 43d8ddb2d679..48a2ed378914 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c | |||
| @@ -254,7 +254,11 @@ static int init_slots(struct controller *ctrl) | |||
| 254 | slot->hp_slot, slot->number, ctrl->slot_device_offset); | 254 | slot->hp_slot, slot->number, ctrl->slot_device_offset); |
| 255 | retval = pci_hp_register(hotplug_slot); | 255 | retval = pci_hp_register(hotplug_slot); |
| 256 | if (retval) { | 256 | if (retval) { |
| 257 | err ("pci_hp_register failed with error %d\n", retval); | 257 | err("pci_hp_register failed with error %d\n", retval); |
| 258 | if (retval == -EEXIST) | ||
| 259 | err("Failed to register slot because of name " | ||
| 260 | "collision. Try \'pciehp_slot_with_bus\' " | ||
| 261 | "module option.\n"); | ||
| 258 | goto error_info; | 262 | goto error_info; |
| 259 | } | 263 | } |
| 260 | /* create additional sysfs entries */ | 264 | /* create additional sysfs entries */ |
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 0a7aa628e955..96a5d55a4983 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c | |||
| @@ -55,16 +55,13 @@ static int queue_interrupt_event(struct slot *p_slot, u32 event_type) | |||
| 55 | return 0; | 55 | return 0; |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl) | 58 | u8 pciehp_handle_attention_button(struct slot *p_slot) |
| 59 | { | 59 | { |
| 60 | struct slot *p_slot; | ||
| 61 | u32 event_type; | 60 | u32 event_type; |
| 62 | 61 | ||
| 63 | /* Attention Button Change */ | 62 | /* Attention Button Change */ |
| 64 | dbg("pciehp: Attention button interrupt received.\n"); | 63 | dbg("pciehp: Attention button interrupt received.\n"); |
| 65 | 64 | ||
| 66 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | ||
| 67 | |||
| 68 | /* | 65 | /* |
| 69 | * Button pressed - See if need to TAKE ACTION!!! | 66 | * Button pressed - See if need to TAKE ACTION!!! |
| 70 | */ | 67 | */ |
| @@ -76,18 +73,15 @@ u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl) | |||
| 76 | return 0; | 73 | return 0; |
| 77 | } | 74 | } |
| 78 | 75 | ||
| 79 | u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl) | 76 | u8 pciehp_handle_switch_change(struct slot *p_slot) |
| 80 | { | 77 | { |
| 81 | struct slot *p_slot; | ||
| 82 | u8 getstatus; | 78 | u8 getstatus; |
| 83 | u32 event_type; | 79 | u32 event_type; |
| 84 | 80 | ||
| 85 | /* Switch Change */ | 81 | /* Switch Change */ |
| 86 | dbg("pciehp: Switch interrupt received.\n"); | 82 | dbg("pciehp: Switch interrupt received.\n"); |
| 87 | 83 | ||
| 88 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | ||
| 89 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 84 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
| 90 | |||
| 91 | if (getstatus) { | 85 | if (getstatus) { |
| 92 | /* | 86 | /* |
| 93 | * Switch opened | 87 | * Switch opened |
| @@ -107,17 +101,14 @@ u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl) | |||
| 107 | return 1; | 101 | return 1; |
| 108 | } | 102 | } |
| 109 | 103 | ||
| 110 | u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl) | 104 | u8 pciehp_handle_presence_change(struct slot *p_slot) |
| 111 | { | 105 | { |
| 112 | struct slot *p_slot; | ||
| 113 | u32 event_type; | 106 | u32 event_type; |
| 114 | u8 presence_save; | 107 | u8 presence_save; |
| 115 | 108 | ||
| 116 | /* Presence Change */ | 109 | /* Presence Change */ |
| 117 | dbg("pciehp: Presence/Notify input change.\n"); | 110 | dbg("pciehp: Presence/Notify input change.\n"); |
| 118 | 111 | ||
| 119 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | ||
| 120 | |||
| 121 | /* Switch is open, assume a presence change | 112 | /* Switch is open, assume a presence change |
| 122 | * Save the presence state | 113 | * Save the presence state |
| 123 | */ | 114 | */ |
| @@ -141,16 +132,13 @@ u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl) | |||
| 141 | return 1; | 132 | return 1; |
| 142 | } | 133 | } |
| 143 | 134 | ||
| 144 | u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl) | 135 | u8 pciehp_handle_power_fault(struct slot *p_slot) |
| 145 | { | 136 | { |
| 146 | struct slot *p_slot; | ||
| 147 | u32 event_type; | 137 | u32 event_type; |
| 148 | 138 | ||
| 149 | /* power fault */ | 139 | /* power fault */ |
| 150 | dbg("pciehp: Power fault interrupt received.\n"); | 140 | dbg("pciehp: Power fault interrupt received.\n"); |
| 151 | 141 | ||
| 152 | p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); | ||
| 153 | |||
| 154 | if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) { | 142 | if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) { |
| 155 | /* | 143 | /* |
| 156 | * power fault Cleared | 144 | * power fault Cleared |
| @@ -163,7 +151,7 @@ u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl) | |||
| 163 | */ | 151 | */ |
| 164 | info("Power fault on Slot(%s)\n", p_slot->name); | 152 | info("Power fault on Slot(%s)\n", p_slot->name); |
| 165 | event_type = INT_POWER_FAULT; | 153 | event_type = INT_POWER_FAULT; |
| 166 | info("power fault bit %x set\n", hp_slot); | 154 | info("power fault bit %x set\n", 0); |
| 167 | } | 155 | } |
| 168 | 156 | ||
| 169 | queue_interrupt_event(p_slot, event_type); | 157 | queue_interrupt_event(p_slot, event_type); |
| @@ -186,6 +174,13 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) | |||
| 186 | } | 174 | } |
| 187 | } | 175 | } |
| 188 | 176 | ||
| 177 | /* | ||
| 178 | * After turning power off, we must wait for at least 1 second | ||
| 179 | * before taking any action that relies on power having been | ||
| 180 | * removed from the slot/adapter. | ||
| 181 | */ | ||
| 182 | msleep(1000); | ||
| 183 | |||
| 189 | if (PWR_LED(ctrl)) | 184 | if (PWR_LED(ctrl)) |
| 190 | pslot->hpc_ops->green_led_off(pslot); | 185 | pslot->hpc_ops->green_led_off(pslot); |
| 191 | 186 | ||
| @@ -289,6 +284,13 @@ static int remove_board(struct slot *p_slot) | |||
| 289 | } | 284 | } |
| 290 | } | 285 | } |
| 291 | 286 | ||
| 287 | /* | ||
| 288 | * After turning power off, we must wait for at least 1 second | ||
| 289 | * before taking any action that relies on power having been | ||
| 290 | * removed from the slot/adapter. | ||
| 291 | */ | ||
| 292 | msleep(1000); | ||
| 293 | |||
| 292 | if (PWR_LED(ctrl)) | 294 | if (PWR_LED(ctrl)) |
| 293 | /* turn off Green LED */ | 295 | /* turn off Green LED */ |
| 294 | p_slot->hpc_ops->green_led_off(p_slot); | 296 | p_slot->hpc_ops->green_led_off(p_slot); |
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 891f81a0400c..79f104963166 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c | |||
| @@ -247,14 +247,38 @@ static inline void pciehp_free_irq(struct controller *ctrl) | |||
| 247 | free_irq(ctrl->pci_dev->irq, ctrl); | 247 | free_irq(ctrl->pci_dev->irq, ctrl); |
| 248 | } | 248 | } |
| 249 | 249 | ||
| 250 | static inline int pcie_wait_cmd(struct controller *ctrl) | 250 | static inline int pcie_poll_cmd(struct controller *ctrl) |
| 251 | { | ||
| 252 | u16 slot_status; | ||
| 253 | int timeout = 1000; | ||
| 254 | |||
| 255 | if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status)) | ||
| 256 | if (slot_status & CMD_COMPLETED) | ||
| 257 | goto completed; | ||
| 258 | for (timeout = 1000; timeout > 0; timeout -= 100) { | ||
| 259 | msleep(100); | ||
| 260 | if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status)) | ||
| 261 | if (slot_status & CMD_COMPLETED) | ||
| 262 | goto completed; | ||
| 263 | } | ||
| 264 | return 0; /* timeout */ | ||
| 265 | |||
| 266 | completed: | ||
| 267 | pciehp_writew(ctrl, SLOTSTATUS, CMD_COMPLETED); | ||
| 268 | return timeout; | ||
| 269 | } | ||
| 270 | |||
| 271 | static inline int pcie_wait_cmd(struct controller *ctrl, int poll) | ||
| 251 | { | 272 | { |
| 252 | int retval = 0; | 273 | int retval = 0; |
| 253 | unsigned int msecs = pciehp_poll_mode ? 2500 : 1000; | 274 | unsigned int msecs = pciehp_poll_mode ? 2500 : 1000; |
| 254 | unsigned long timeout = msecs_to_jiffies(msecs); | 275 | unsigned long timeout = msecs_to_jiffies(msecs); |
| 255 | int rc; | 276 | int rc; |
| 256 | 277 | ||
| 257 | rc = wait_event_interruptible_timeout(ctrl->queue, | 278 | if (poll) |
| 279 | rc = pcie_poll_cmd(ctrl); | ||
| 280 | else | ||
| 281 | rc = wait_event_interruptible_timeout(ctrl->queue, | ||
| 258 | !ctrl->cmd_busy, timeout); | 282 | !ctrl->cmd_busy, timeout); |
| 259 | if (!rc) | 283 | if (!rc) |
| 260 | dbg("Command not completed in 1000 msec\n"); | 284 | dbg("Command not completed in 1000 msec\n"); |
| @@ -286,12 +310,28 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) | |||
| 286 | goto out; | 310 | goto out; |
| 287 | } | 311 | } |
| 288 | 312 | ||
| 289 | if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) { | 313 | if (slot_status & CMD_COMPLETED) { |
| 290 | /* After 1 sec and CMD_COMPLETED still not set, just | 314 | if (!ctrl->no_cmd_complete) { |
| 291 | proceed forward to issue the next command according | 315 | /* |
| 292 | to spec. Just print out the error message */ | 316 | * After 1 sec and CMD_COMPLETED still not set, just |
| 293 | dbg("%s: CMD_COMPLETED not clear after 1 sec.\n", | 317 | * proceed forward to issue the next command according |
| 294 | __func__); | 318 | * to spec. Just print out the error message. |
| 319 | */ | ||
| 320 | dbg("%s: CMD_COMPLETED not clear after 1 sec.\n", | ||
| 321 | __func__); | ||
| 322 | } else if (!NO_CMD_CMPL(ctrl)) { | ||
| 323 | /* | ||
| 324 | * This controller semms to notify of command completed | ||
| 325 | * event even though it supports none of power | ||
| 326 | * controller, attention led, power led and EMI. | ||
| 327 | */ | ||
| 328 | dbg("%s: Unexpected CMD_COMPLETED. Need to wait for " | ||
| 329 | "command completed event.\n", __func__); | ||
| 330 | ctrl->no_cmd_complete = 0; | ||
| 331 | } else { | ||
| 332 | dbg("%s: Unexpected CMD_COMPLETED. Maybe the " | ||
| 333 | "controller is broken.\n", __func__); | ||
| 334 | } | ||
| 295 | } | 335 | } |
| 296 | 336 | ||
| 297 | retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); | 337 | retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); |
| @@ -315,8 +355,18 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) | |||
| 315 | /* | 355 | /* |
| 316 | * Wait for command completion. | 356 | * Wait for command completion. |
| 317 | */ | 357 | */ |
| 318 | if (!retval) | 358 | if (!retval && !ctrl->no_cmd_complete) { |
| 319 | retval = pcie_wait_cmd(ctrl); | 359 | int poll = 0; |
| 360 | /* | ||
| 361 | * if hotplug interrupt is not enabled or command | ||
| 362 | * completed interrupt is not enabled, we need to poll | ||
| 363 | * command completed event. | ||
| 364 | */ | ||
| 365 | if (!(slot_ctrl & HP_INTR_ENABLE) || | ||
| 366 | !(slot_ctrl & CMD_CMPL_INTR_ENABLE)) | ||
| 367 | poll = 1; | ||
| 368 | retval = pcie_wait_cmd(ctrl, poll); | ||
| 369 | } | ||
| 320 | out: | 370 | out: |
| 321 | mutex_unlock(&ctrl->ctrl_lock); | 371 | mutex_unlock(&ctrl->ctrl_lock); |
| 322 | return retval; | 372 | return retval; |
| @@ -704,13 +754,6 @@ static int hpc_power_off_slot(struct slot * slot) | |||
| 704 | } | 754 | } |
| 705 | dbg("%s: SLOTCTRL %x write cmd %x\n", | 755 | dbg("%s: SLOTCTRL %x write cmd %x\n", |
| 706 | __func__, ctrl->cap_base + SLOTCTRL, slot_cmd); | 756 | __func__, ctrl->cap_base + SLOTCTRL, slot_cmd); |
| 707 | |||
| 708 | /* | ||
| 709 | * After turning power off, we must wait for at least 1 second | ||
| 710 | * before taking any action that relies on power having been | ||
| 711 | * removed from the slot/adapter. | ||
| 712 | */ | ||
| 713 | msleep(1000); | ||
| 714 | out: | 757 | out: |
| 715 | if (changed) | 758 | if (changed) |
| 716 | pcie_unmask_bad_dllp(ctrl); | 759 | pcie_unmask_bad_dllp(ctrl); |
| @@ -722,6 +765,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) | |||
| 722 | { | 765 | { |
| 723 | struct controller *ctrl = (struct controller *)dev_id; | 766 | struct controller *ctrl = (struct controller *)dev_id; |
| 724 | u16 detected, intr_loc; | 767 | u16 detected, intr_loc; |
| 768 | struct slot *p_slot; | ||
| 725 | 769 | ||
| 726 | /* | 770 | /* |
| 727 | * In order to guarantee that all interrupt events are | 771 | * In order to guarantee that all interrupt events are |
| @@ -756,21 +800,38 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) | |||
| 756 | wake_up_interruptible(&ctrl->queue); | 800 | wake_up_interruptible(&ctrl->queue); |
| 757 | } | 801 | } |
| 758 | 802 | ||
| 803 | if (!(intr_loc & ~CMD_COMPLETED)) | ||
| 804 | return IRQ_HANDLED; | ||
| 805 | |||
| 806 | /* | ||
| 807 | * Return without handling events if this handler routine is | ||
| 808 | * called before controller initialization is done. This may | ||
| 809 | * happen if hotplug event or another interrupt that shares | ||
| 810 | * the IRQ with pciehp arrives before slot initialization is | ||
| 811 | * done after interrupt handler is registered. | ||
| 812 | * | ||
| 813 | * FIXME - Need more structural fixes. We need to be ready to | ||
| 814 | * handle the event before installing interrupt handler. | ||
| 815 | */ | ||
| 816 | p_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); | ||
| 817 | if (!p_slot || !p_slot->hpc_ops) | ||
| 818 | return IRQ_HANDLED; | ||
| 819 | |||
| 759 | /* Check MRL Sensor Changed */ | 820 | /* Check MRL Sensor Changed */ |
| 760 | if (intr_loc & MRL_SENS_CHANGED) | 821 | if (intr_loc & MRL_SENS_CHANGED) |
| 761 | pciehp_handle_switch_change(0, ctrl); | 822 | pciehp_handle_switch_change(p_slot); |
| 762 | 823 | ||
| 763 | /* Check Attention Button Pressed */ | 824 | /* Check Attention Button Pressed */ |
| 764 | if (intr_loc & ATTN_BUTTN_PRESSED) | 825 | if (intr_loc & ATTN_BUTTN_PRESSED) |
| 765 | pciehp_handle_attention_button(0, ctrl); | 826 | pciehp_handle_attention_button(p_slot); |
| 766 | 827 | ||
| 767 | /* Check Presence Detect Changed */ | 828 | /* Check Presence Detect Changed */ |
| 768 | if (intr_loc & PRSN_DETECT_CHANGED) | 829 | if (intr_loc & PRSN_DETECT_CHANGED) |
| 769 | pciehp_handle_presence_change(0, ctrl); | 830 | pciehp_handle_presence_change(p_slot); |
| 770 | 831 | ||
| 771 | /* Check Power Fault Detected */ | 832 | /* Check Power Fault Detected */ |
| 772 | if (intr_loc & PWR_FAULT_DETECTED) | 833 | if (intr_loc & PWR_FAULT_DETECTED) |
| 773 | pciehp_handle_power_fault(0, ctrl); | 834 | pciehp_handle_power_fault(p_slot); |
| 774 | 835 | ||
| 775 | return IRQ_HANDLED; | 836 | return IRQ_HANDLED; |
| 776 | } | 837 | } |
| @@ -1028,6 +1089,12 @@ static int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) | |||
| 1028 | static int pcie_init_hardware_part1(struct controller *ctrl, | 1089 | static int pcie_init_hardware_part1(struct controller *ctrl, |
| 1029 | struct pcie_device *dev) | 1090 | struct pcie_device *dev) |
| 1030 | { | 1091 | { |
| 1092 | /* Clear all remaining event bits in Slot Status register */ | ||
| 1093 | if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) { | ||
| 1094 | err("%s: Cannot write to SLOTSTATUS register\n", __func__); | ||
| 1095 | return -1; | ||
| 1096 | } | ||
| 1097 | |||
| 1031 | /* Mask Hot-plug Interrupt Enable */ | 1098 | /* Mask Hot-plug Interrupt Enable */ |
| 1032 | if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE)) { | 1099 | if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE)) { |
| 1033 | err("%s: Cannot mask hotplug interrupt enable\n", __func__); | 1100 | err("%s: Cannot mask hotplug interrupt enable\n", __func__); |
| @@ -1040,16 +1107,6 @@ int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev) | |||
| 1040 | { | 1107 | { |
| 1041 | u16 cmd, mask; | 1108 | u16 cmd, mask; |
| 1042 | 1109 | ||
| 1043 | /* | ||
| 1044 | * We need to clear all events before enabling hotplug interrupt | ||
| 1045 | * notification mechanism in order for hotplug controler to | ||
| 1046 | * generate interrupts. | ||
| 1047 | */ | ||
| 1048 | if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) { | ||
| 1049 | err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); | ||
| 1050 | return -1; | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | cmd = PRSN_DETECT_ENABLE; | 1110 | cmd = PRSN_DETECT_ENABLE; |
| 1054 | if (ATTN_BUTTN(ctrl)) | 1111 | if (ATTN_BUTTN(ctrl)) |
| 1055 | cmd |= ATTN_BUTTN_ENABLE; | 1112 | cmd |= ATTN_BUTTN_ENABLE; |
| @@ -1116,6 +1173,7 @@ static inline void dbg_ctrl(struct controller *ctrl) | |||
| 1116 | dbg(" Power Indicator : %3s\n", PWR_LED(ctrl) ? "yes" : "no"); | 1173 | dbg(" Power Indicator : %3s\n", PWR_LED(ctrl) ? "yes" : "no"); |
| 1117 | dbg(" Hot-Plug Surprise : %3s\n", HP_SUPR_RM(ctrl) ? "yes" : "no"); | 1174 | dbg(" Hot-Plug Surprise : %3s\n", HP_SUPR_RM(ctrl) ? "yes" : "no"); |
| 1118 | dbg(" EMI Present : %3s\n", EMI(ctrl) ? "yes" : "no"); | 1175 | dbg(" EMI Present : %3s\n", EMI(ctrl) ? "yes" : "no"); |
| 1176 | dbg(" Comamnd Completed : %3s\n", NO_CMD_CMPL(ctrl)? "no" : "yes"); | ||
| 1119 | pciehp_readw(ctrl, SLOTSTATUS, ®16); | 1177 | pciehp_readw(ctrl, SLOTSTATUS, ®16); |
| 1120 | dbg("Slot Status : 0x%04x\n", reg16); | 1178 | dbg("Slot Status : 0x%04x\n", reg16); |
| 1121 | pciehp_readw(ctrl, SLOTSTATUS, ®16); | 1179 | pciehp_readw(ctrl, SLOTSTATUS, ®16); |
| @@ -1147,6 +1205,15 @@ int pcie_init(struct controller *ctrl, struct pcie_device *dev) | |||
| 1147 | mutex_init(&ctrl->ctrl_lock); | 1205 | mutex_init(&ctrl->ctrl_lock); |
| 1148 | init_waitqueue_head(&ctrl->queue); | 1206 | init_waitqueue_head(&ctrl->queue); |
| 1149 | dbg_ctrl(ctrl); | 1207 | dbg_ctrl(ctrl); |
| 1208 | /* | ||
| 1209 | * Controller doesn't notify of command completion if the "No | ||
| 1210 | * Command Completed Support" bit is set in Slot Capability | ||
| 1211 | * register or the controller supports none of power | ||
| 1212 | * controller, attention led, power led and EMI. | ||
| 1213 | */ | ||
| 1214 | if (NO_CMD_CMPL(ctrl) || | ||
| 1215 | !(POWER_CTRL(ctrl) | ATTN_LED(ctrl) | PWR_LED(ctrl) | EMI(ctrl))) | ||
| 1216 | ctrl->no_cmd_complete = 1; | ||
| 1150 | 1217 | ||
| 1151 | info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", | 1218 | info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", |
| 1152 | pdev->vendor, pdev->device, | 1219 | pdev->vendor, pdev->device, |
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 1648076600fc..97848654652a 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c | |||
| @@ -162,6 +162,10 @@ static int init_slots(struct controller *ctrl) | |||
| 162 | retval = pci_hp_register(slot->hotplug_slot); | 162 | retval = pci_hp_register(slot->hotplug_slot); |
| 163 | if (retval) { | 163 | if (retval) { |
| 164 | err("pci_hp_register failed with error %d\n", retval); | 164 | err("pci_hp_register failed with error %d\n", retval); |
| 165 | if (retval == -EEXIST) | ||
| 166 | err("Failed to register slot because of name " | ||
| 167 | "collision. Try \'shpchp_slot_with_bus\' " | ||
| 168 | "module option.\n"); | ||
| 165 | goto error_info; | 169 | goto error_info; |
| 166 | } | 170 | } |
| 167 | 171 | ||
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 61fedb2448b6..f82495583e63 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c | |||
| @@ -506,6 +506,23 @@ static void free_link_state(struct pci_dev *pdev) | |||
| 506 | pdev->link_state = NULL; | 506 | pdev->link_state = NULL; |
| 507 | } | 507 | } |
| 508 | 508 | ||
| 509 | static int pcie_aspm_sanity_check(struct pci_dev *pdev) | ||
| 510 | { | ||
| 511 | struct pci_dev *child_dev; | ||
| 512 | int child_pos; | ||
| 513 | |||
| 514 | /* | ||
| 515 | * Some functions in a slot might not all be PCIE functions, very | ||
| 516 | * strange. Disable ASPM for the whole slot | ||
| 517 | */ | ||
| 518 | list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { | ||
| 519 | child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); | ||
| 520 | if (!child_pos) | ||
| 521 | return -EINVAL; | ||
| 522 | } | ||
| 523 | return 0; | ||
| 524 | } | ||
| 525 | |||
| 509 | /* | 526 | /* |
| 510 | * pcie_aspm_init_link_state: Initiate PCI express link state. | 527 | * pcie_aspm_init_link_state: Initiate PCI express link state. |
| 511 | * It is called after the pcie and its children devices are scaned. | 528 | * It is called after the pcie and its children devices are scaned. |
| @@ -526,6 +543,9 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) | |||
| 526 | if (list_empty(&pdev->subordinate->devices)) | 543 | if (list_empty(&pdev->subordinate->devices)) |
| 527 | goto out; | 544 | goto out; |
| 528 | 545 | ||
| 546 | if (pcie_aspm_sanity_check(pdev)) | ||
| 547 | goto out; | ||
| 548 | |||
| 529 | mutex_lock(&aspm_lock); | 549 | mutex_lock(&aspm_lock); |
| 530 | 550 | ||
| 531 | link_state = kzalloc(sizeof(*link_state), GFP_KERNEL); | 551 | link_state = kzalloc(sizeof(*link_state), GFP_KERNEL); |
