diff options
-rw-r--r-- | drivers/pci/hotplug/pciehp.h | 16 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_acpi.c | 17 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_core.c | 120 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 20 |
4 files changed, 76 insertions, 97 deletions
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 36faa9a8e18f..af397b1291ea 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h | |||
@@ -80,7 +80,6 @@ struct slot { | |||
80 | struct controller *ctrl; | 80 | struct controller *ctrl; |
81 | struct hpc_ops *hpc_ops; | 81 | struct hpc_ops *hpc_ops; |
82 | struct hotplug_slot *hotplug_slot; | 82 | struct hotplug_slot *hotplug_slot; |
83 | struct list_head slot_list; | ||
84 | struct delayed_work work; /* work for button event */ | 83 | struct delayed_work work; /* work for button event */ |
85 | struct mutex lock; | 84 | struct mutex lock; |
86 | }; | 85 | }; |
@@ -98,7 +97,7 @@ struct controller { | |||
98 | int slot_num_inc; /* 1 or -1 */ | 97 | int slot_num_inc; /* 1 or -1 */ |
99 | struct pci_dev *pci_dev; | 98 | struct pci_dev *pci_dev; |
100 | struct pcie_device *pcie; /* PCI Express port service */ | 99 | struct pcie_device *pcie; /* PCI Express port service */ |
101 | struct list_head slot_list; | 100 | struct slot *slot; |
102 | struct hpc_ops *hpc_ops; | 101 | struct hpc_ops *hpc_ops; |
103 | wait_queue_head_t queue; /* sleep & wake process */ | 102 | wait_queue_head_t queue; /* sleep & wake process */ |
104 | u8 slot_device_offset; | 103 | u8 slot_device_offset; |
@@ -181,19 +180,6 @@ static inline const char *slot_name(struct slot *slot) | |||
181 | return hotplug_slot_name(slot->hotplug_slot); | 180 | return hotplug_slot_name(slot->hotplug_slot); |
182 | } | 181 | } |
183 | 182 | ||
184 | static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device) | ||
185 | { | ||
186 | struct slot *slot; | ||
187 | |||
188 | list_for_each_entry(slot, &ctrl->slot_list, slot_list) { | ||
189 | if (slot->device == device) | ||
190 | return slot; | ||
191 | } | ||
192 | |||
193 | ctrl_err(ctrl, "Slot (device=0x%02x) not found\n", device); | ||
194 | return NULL; | ||
195 | } | ||
196 | |||
197 | struct hpc_ops { | 183 | struct hpc_ops { |
198 | int (*power_on_slot)(struct slot *slot); | 184 | int (*power_on_slot)(struct slot *slot); |
199 | int (*power_off_slot)(struct slot *slot); | 185 | int (*power_off_slot)(struct slot *slot); |
diff --git a/drivers/pci/hotplug/pciehp_acpi.c b/drivers/pci/hotplug/pciehp_acpi.c index 7163e6a6cfae..37c8d3d0323e 100644 --- a/drivers/pci/hotplug/pciehp_acpi.c +++ b/drivers/pci/hotplug/pciehp_acpi.c | |||
@@ -33,6 +33,11 @@ | |||
33 | #define PCIEHP_DETECT_AUTO (2) | 33 | #define PCIEHP_DETECT_AUTO (2) |
34 | #define PCIEHP_DETECT_DEFAULT PCIEHP_DETECT_AUTO | 34 | #define PCIEHP_DETECT_DEFAULT PCIEHP_DETECT_AUTO |
35 | 35 | ||
36 | struct dummy_slot { | ||
37 | u32 number; | ||
38 | struct list_head list; | ||
39 | }; | ||
40 | |||
36 | static int slot_detection_mode; | 41 | static int slot_detection_mode; |
37 | static char *pciehp_detect_mode; | 42 | static char *pciehp_detect_mode; |
38 | module_param(pciehp_detect_mode, charp, 0444); | 43 | module_param(pciehp_detect_mode, charp, 0444); |
@@ -77,7 +82,7 @@ static int __init dummy_probe(struct pcie_device *dev) | |||
77 | int pos; | 82 | int pos; |
78 | u32 slot_cap; | 83 | u32 slot_cap; |
79 | acpi_handle handle; | 84 | acpi_handle handle; |
80 | struct slot *slot, *tmp; | 85 | struct dummy_slot *slot, *tmp; |
81 | struct pci_dev *pdev = dev->port; | 86 | struct pci_dev *pdev = dev->port; |
82 | /* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */ | 87 | /* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */ |
83 | if (pciehp_get_hp_hw_control_from_firmware(pdev)) | 88 | if (pciehp_get_hp_hw_control_from_firmware(pdev)) |
@@ -89,11 +94,11 @@ static int __init dummy_probe(struct pcie_device *dev) | |||
89 | if (!slot) | 94 | if (!slot) |
90 | return -ENOMEM; | 95 | return -ENOMEM; |
91 | slot->number = slot_cap >> 19; | 96 | slot->number = slot_cap >> 19; |
92 | list_for_each_entry(tmp, &dummy_slots, slot_list) { | 97 | list_for_each_entry(tmp, &dummy_slots, list) { |
93 | if (tmp->number == slot->number) | 98 | if (tmp->number == slot->number) |
94 | dup_slot_id++; | 99 | dup_slot_id++; |
95 | } | 100 | } |
96 | list_add_tail(&slot->slot_list, &dummy_slots); | 101 | list_add_tail(&slot->list, &dummy_slots); |
97 | handle = DEVICE_ACPI_HANDLE(&pdev->dev); | 102 | handle = DEVICE_ACPI_HANDLE(&pdev->dev); |
98 | if (!acpi_slot_detected && acpi_pci_detect_ejectable(handle)) | 103 | if (!acpi_slot_detected && acpi_pci_detect_ejectable(handle)) |
99 | acpi_slot_detected = 1; | 104 | acpi_slot_detected = 1; |
@@ -109,11 +114,11 @@ static struct pcie_port_service_driver __initdata dummy_driver = { | |||
109 | 114 | ||
110 | static int __init select_detection_mode(void) | 115 | static int __init select_detection_mode(void) |
111 | { | 116 | { |
112 | struct slot *slot, *tmp; | 117 | struct dummy_slot *slot, *tmp; |
113 | pcie_port_service_register(&dummy_driver); | 118 | pcie_port_service_register(&dummy_driver); |
114 | pcie_port_service_unregister(&dummy_driver); | 119 | pcie_port_service_unregister(&dummy_driver); |
115 | list_for_each_entry_safe(slot, tmp, &dummy_slots, slot_list) { | 120 | list_for_each_entry_safe(slot, tmp, &dummy_slots, list) { |
116 | list_del(&slot->slot_list); | 121 | list_del(&slot->list); |
117 | kfree(slot); | 122 | kfree(slot); |
118 | } | 123 | } |
119 | if (acpi_slot_detected && dup_slot_id) | 124 | if (acpi_slot_detected && dup_slot_id) |
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 2317557fdee6..d2cec882a2f5 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c | |||
@@ -99,65 +99,59 @@ static void release_slot(struct hotplug_slot *hotplug_slot) | |||
99 | kfree(hotplug_slot); | 99 | kfree(hotplug_slot); |
100 | } | 100 | } |
101 | 101 | ||
102 | static int init_slots(struct controller *ctrl) | 102 | static int init_slot(struct controller *ctrl) |
103 | { | 103 | { |
104 | struct slot *slot; | 104 | struct slot *slot = ctrl->slot; |
105 | struct hotplug_slot *hotplug_slot; | 105 | struct hotplug_slot *hotplug = NULL; |
106 | struct hotplug_slot_info *info; | 106 | struct hotplug_slot_info *info = NULL; |
107 | char name[SLOT_NAME_SIZE]; | 107 | char name[SLOT_NAME_SIZE]; |
108 | int retval = -ENOMEM; | 108 | int retval = -ENOMEM; |
109 | 109 | ||
110 | list_for_each_entry(slot, &ctrl->slot_list, slot_list) { | 110 | hotplug = kzalloc(sizeof(*hotplug), GFP_KERNEL); |
111 | hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL); | 111 | if (!hotplug) |
112 | if (!hotplug_slot) | 112 | goto out; |
113 | goto error; | 113 | |
114 | 114 | info = kzalloc(sizeof(*info), GFP_KERNEL); | |
115 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 115 | if (!info) |
116 | if (!info) | 116 | goto out; |
117 | goto error_hpslot; | 117 | |
118 | 118 | /* register this slot with the hotplug pci core */ | |
119 | /* register this slot with the hotplug pci core */ | 119 | hotplug->info = info; |
120 | hotplug_slot->info = info; | 120 | hotplug->private = slot; |
121 | hotplug_slot->private = slot; | 121 | hotplug->release = &release_slot; |
122 | hotplug_slot->release = &release_slot; | 122 | hotplug->ops = &pciehp_hotplug_slot_ops; |
123 | hotplug_slot->ops = &pciehp_hotplug_slot_ops; | 123 | slot->hotplug_slot = hotplug; |
124 | slot->hotplug_slot = hotplug_slot; | 124 | snprintf(name, SLOT_NAME_SIZE, "%u", slot->number); |
125 | snprintf(name, SLOT_NAME_SIZE, "%u", slot->number); | 125 | |
126 | 126 | ctrl_dbg(ctrl, "Registering domain:bus:dev=%04x:%02x:%02x " | |
127 | ctrl_dbg(ctrl, "Registering domain:bus:dev=%04x:%02x:%02x " | 127 | "hp_slot=%x sun=%x slot_device_offset=%x\n", |
128 | "hp_slot=%x sun=%x slot_device_offset=%x\n", | 128 | pci_domain_nr(ctrl->pci_dev->subordinate), |
129 | pci_domain_nr(ctrl->pci_dev->subordinate), | 129 | slot->bus, slot->device, slot->hp_slot, slot->number, |
130 | slot->bus, slot->device, slot->hp_slot, slot->number, | 130 | ctrl->slot_device_offset); |
131 | ctrl->slot_device_offset); | 131 | retval = pci_hp_register(hotplug, |
132 | retval = pci_hp_register(hotplug_slot, | 132 | ctrl->pci_dev->subordinate, |
133 | ctrl->pci_dev->subordinate, | 133 | slot->device, |
134 | slot->device, | 134 | name); |
135 | name); | 135 | if (retval) { |
136 | if (retval) { | 136 | ctrl_err(ctrl, |
137 | ctrl_err(ctrl, "pci_hp_register failed with error %d\n", | 137 | "pci_hp_register failed with error %d\n", retval); |
138 | retval); | 138 | goto out; |
139 | goto error_info; | 139 | } |
140 | } | 140 | get_power_status(hotplug, &info->power_status); |
141 | get_power_status(hotplug_slot, &info->power_status); | 141 | get_attention_status(hotplug, &info->attention_status); |
142 | get_attention_status(hotplug_slot, &info->attention_status); | 142 | get_latch_status(hotplug, &info->latch_status); |
143 | get_latch_status(hotplug_slot, &info->latch_status); | 143 | get_adapter_status(hotplug, &info->adapter_status); |
144 | get_adapter_status(hotplug_slot, &info->adapter_status); | 144 | out: |
145 | if (retval) { | ||
146 | kfree(info); | ||
147 | kfree(hotplug); | ||
145 | } | 148 | } |
146 | |||
147 | return 0; | ||
148 | error_info: | ||
149 | kfree(info); | ||
150 | error_hpslot: | ||
151 | kfree(hotplug_slot); | ||
152 | error: | ||
153 | return retval; | 149 | return retval; |
154 | } | 150 | } |
155 | 151 | ||
156 | static void cleanup_slots(struct controller *ctrl) | 152 | static void cleanup_slot(struct controller *ctrl) |
157 | { | 153 | { |
158 | struct slot *slot; | 154 | pci_hp_deregister(ctrl->slot->hotplug_slot); |
159 | list_for_each_entry(slot, &ctrl->slot_list, slot_list) | ||
160 | pci_hp_deregister(slot->hotplug_slot); | ||
161 | } | 155 | } |
162 | 156 | ||
163 | /* | 157 | /* |
@@ -295,7 +289,7 @@ static int pciehp_probe(struct pcie_device *dev) | |||
295 | { | 289 | { |
296 | int rc; | 290 | int rc; |
297 | struct controller *ctrl; | 291 | struct controller *ctrl; |
298 | struct slot *t_slot; | 292 | struct slot *slot; |
299 | u8 value; | 293 | u8 value; |
300 | struct pci_dev *pdev = dev->port; | 294 | struct pci_dev *pdev = dev->port; |
301 | 295 | ||
@@ -314,7 +308,7 @@ static int pciehp_probe(struct pcie_device *dev) | |||
314 | set_service_data(dev, ctrl); | 308 | set_service_data(dev, ctrl); |
315 | 309 | ||
316 | /* Setup the slot information structures */ | 310 | /* Setup the slot information structures */ |
317 | rc = init_slots(ctrl); | 311 | rc = init_slot(ctrl); |
318 | if (rc) { | 312 | if (rc) { |
319 | if (rc == -EBUSY) | 313 | if (rc == -EBUSY) |
320 | ctrl_warn(ctrl, "Slot already registered by another " | 314 | ctrl_warn(ctrl, "Slot already registered by another " |
@@ -332,15 +326,15 @@ static int pciehp_probe(struct pcie_device *dev) | |||
332 | } | 326 | } |
333 | 327 | ||
334 | /* Check if slot is occupied */ | 328 | /* Check if slot is occupied */ |
335 | t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); | 329 | slot = ctrl->slot; |
336 | t_slot->hpc_ops->get_adapter_status(t_slot, &value); | 330 | slot->hpc_ops->get_adapter_status(slot, &value); |
337 | if (value) { | 331 | if (value) { |
338 | if (pciehp_force) | 332 | if (pciehp_force) |
339 | pciehp_enable_slot(t_slot); | 333 | pciehp_enable_slot(slot); |
340 | } else { | 334 | } else { |
341 | /* Power off slot if not occupied */ | 335 | /* Power off slot if not occupied */ |
342 | if (POWER_CTRL(ctrl)) { | 336 | if (POWER_CTRL(ctrl)) { |
343 | rc = t_slot->hpc_ops->power_off_slot(t_slot); | 337 | rc = slot->hpc_ops->power_off_slot(slot); |
344 | if (rc) | 338 | if (rc) |
345 | goto err_out_free_ctrl_slot; | 339 | goto err_out_free_ctrl_slot; |
346 | } | 340 | } |
@@ -349,7 +343,7 @@ static int pciehp_probe(struct pcie_device *dev) | |||
349 | return 0; | 343 | return 0; |
350 | 344 | ||
351 | err_out_free_ctrl_slot: | 345 | err_out_free_ctrl_slot: |
352 | cleanup_slots(ctrl); | 346 | cleanup_slot(ctrl); |
353 | err_out_release_ctlr: | 347 | err_out_release_ctlr: |
354 | ctrl->hpc_ops->release_ctlr(ctrl); | 348 | ctrl->hpc_ops->release_ctlr(ctrl); |
355 | err_out_none: | 349 | err_out_none: |
@@ -360,7 +354,7 @@ static void pciehp_remove (struct pcie_device *dev) | |||
360 | { | 354 | { |
361 | struct controller *ctrl = get_service_data(dev); | 355 | struct controller *ctrl = get_service_data(dev); |
362 | 356 | ||
363 | cleanup_slots(ctrl); | 357 | cleanup_slot(ctrl); |
364 | ctrl->hpc_ops->release_ctlr(ctrl); | 358 | ctrl->hpc_ops->release_ctlr(ctrl); |
365 | } | 359 | } |
366 | 360 | ||
@@ -376,20 +370,20 @@ static int pciehp_resume (struct pcie_device *dev) | |||
376 | dev_info(&dev->device, "%s ENTRY\n", __func__); | 370 | dev_info(&dev->device, "%s ENTRY\n", __func__); |
377 | if (pciehp_force) { | 371 | if (pciehp_force) { |
378 | struct controller *ctrl = get_service_data(dev); | 372 | struct controller *ctrl = get_service_data(dev); |
379 | struct slot *t_slot; | 373 | struct slot *slot; |
380 | u8 status; | 374 | u8 status; |
381 | 375 | ||
382 | /* reinitialize the chipset's event detection logic */ | 376 | /* reinitialize the chipset's event detection logic */ |
383 | pcie_enable_notification(ctrl); | 377 | pcie_enable_notification(ctrl); |
384 | 378 | ||
385 | t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); | 379 | slot = ctrl->slot; |
386 | 380 | ||
387 | /* Check if slot is occupied */ | 381 | /* Check if slot is occupied */ |
388 | t_slot->hpc_ops->get_adapter_status(t_slot, &status); | 382 | slot->hpc_ops->get_adapter_status(slot, &status); |
389 | if (status) | 383 | if (status) |
390 | pciehp_enable_slot(t_slot); | 384 | pciehp_enable_slot(slot); |
391 | else | 385 | else |
392 | pciehp_disable_slot(t_slot); | 386 | pciehp_disable_slot(slot); |
393 | } | 387 | } |
394 | return 0; | 388 | return 0; |
395 | } | 389 | } |
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 271f917b6f2c..cb0cf2cae7b7 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c | |||
@@ -614,8 +614,8 @@ static int hpc_power_off_slot(struct slot * slot) | |||
614 | static irqreturn_t pcie_isr(int irq, void *dev_id) | 614 | static irqreturn_t pcie_isr(int irq, void *dev_id) |
615 | { | 615 | { |
616 | struct controller *ctrl = (struct controller *)dev_id; | 616 | struct controller *ctrl = (struct controller *)dev_id; |
617 | struct slot *slot = ctrl->slot; | ||
617 | u16 detected, intr_loc; | 618 | u16 detected, intr_loc; |
618 | struct slot *p_slot; | ||
619 | 619 | ||
620 | /* | 620 | /* |
621 | * In order to guarantee that all interrupt events are | 621 | * In order to guarantee that all interrupt events are |
@@ -656,24 +656,22 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) | |||
656 | if (!(intr_loc & ~PCI_EXP_SLTSTA_CC)) | 656 | if (!(intr_loc & ~PCI_EXP_SLTSTA_CC)) |
657 | return IRQ_HANDLED; | 657 | return IRQ_HANDLED; |
658 | 658 | ||
659 | p_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); | ||
660 | |||
661 | /* Check MRL Sensor Changed */ | 659 | /* Check MRL Sensor Changed */ |
662 | if (intr_loc & PCI_EXP_SLTSTA_MRLSC) | 660 | if (intr_loc & PCI_EXP_SLTSTA_MRLSC) |
663 | pciehp_handle_switch_change(p_slot); | 661 | pciehp_handle_switch_change(slot); |
664 | 662 | ||
665 | /* Check Attention Button Pressed */ | 663 | /* Check Attention Button Pressed */ |
666 | if (intr_loc & PCI_EXP_SLTSTA_ABP) | 664 | if (intr_loc & PCI_EXP_SLTSTA_ABP) |
667 | pciehp_handle_attention_button(p_slot); | 665 | pciehp_handle_attention_button(slot); |
668 | 666 | ||
669 | /* Check Presence Detect Changed */ | 667 | /* Check Presence Detect Changed */ |
670 | if (intr_loc & PCI_EXP_SLTSTA_PDC) | 668 | if (intr_loc & PCI_EXP_SLTSTA_PDC) |
671 | pciehp_handle_presence_change(p_slot); | 669 | pciehp_handle_presence_change(slot); |
672 | 670 | ||
673 | /* Check Power Fault Detected */ | 671 | /* Check Power Fault Detected */ |
674 | if ((intr_loc & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) { | 672 | if ((intr_loc & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) { |
675 | ctrl->power_fault_detected = 1; | 673 | ctrl->power_fault_detected = 1; |
676 | pciehp_handle_power_fault(p_slot); | 674 | pciehp_handle_power_fault(slot); |
677 | } | 675 | } |
678 | return IRQ_HANDLED; | 676 | return IRQ_HANDLED; |
679 | } | 677 | } |
@@ -938,15 +936,13 @@ static int pcie_init_slot(struct controller *ctrl) | |||
938 | slot->number = ctrl->first_slot; | 936 | slot->number = ctrl->first_slot; |
939 | mutex_init(&slot->lock); | 937 | mutex_init(&slot->lock); |
940 | INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work); | 938 | INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work); |
941 | list_add(&slot->slot_list, &ctrl->slot_list); | 939 | ctrl->slot = slot; |
942 | return 0; | 940 | return 0; |
943 | } | 941 | } |
944 | 942 | ||
945 | static void pcie_cleanup_slot(struct controller *ctrl) | 943 | static void pcie_cleanup_slot(struct controller *ctrl) |
946 | { | 944 | { |
947 | struct slot *slot; | 945 | struct slot *slot = ctrl->slot; |
948 | slot = list_first_entry(&ctrl->slot_list, struct slot, slot_list); | ||
949 | list_del(&slot->slot_list); | ||
950 | cancel_delayed_work(&slot->work); | 946 | cancel_delayed_work(&slot->work); |
951 | flush_scheduled_work(); | 947 | flush_scheduled_work(); |
952 | flush_workqueue(pciehp_wq); | 948 | flush_workqueue(pciehp_wq); |
@@ -1014,8 +1010,6 @@ struct controller *pcie_init(struct pcie_device *dev) | |||
1014 | dev_err(&dev->device, "%s: Out of memory\n", __func__); | 1010 | dev_err(&dev->device, "%s: Out of memory\n", __func__); |
1015 | goto abort; | 1011 | goto abort; |
1016 | } | 1012 | } |
1017 | INIT_LIST_HEAD(&ctrl->slot_list); | ||
1018 | |||
1019 | ctrl->pcie = dev; | 1013 | ctrl->pcie = dev; |
1020 | ctrl->pci_dev = pdev; | 1014 | ctrl->pci_dev = pdev; |
1021 | ctrl->cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP); | 1015 | ctrl->cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP); |