diff options
author | Jeff Garzik <jeff@garzik.org> | 2006-06-22 22:51:46 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-06-22 22:51:46 -0400 |
commit | dbe1ab9514c231c9b062140a107d9dea0eabefcc (patch) | |
tree | 0001c7143cf923fc704215f0a0e54221e9e5cbb9 /drivers/pci | |
parent | 612eff0e3715a6faff5ba1b74873b99e036c59fe (diff) | |
parent | d588fcbe5a7ba8bba2cebf7799ab2d573717a806 (diff) |
Merge branch 'master' into upstream
Diffstat (limited to 'drivers/pci')
31 files changed, 1836 insertions, 931 deletions
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 6707df968934..f2d152b818f0 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile | |||
@@ -26,7 +26,11 @@ obj-$(CONFIG_PPC32) += setup-irq.o | |||
26 | obj-$(CONFIG_PPC64) += setup-bus.o | 26 | obj-$(CONFIG_PPC64) += setup-bus.o |
27 | obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o | 27 | obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o |
28 | obj-$(CONFIG_X86_VISWS) += setup-irq.o | 28 | obj-$(CONFIG_X86_VISWS) += setup-irq.o |
29 | obj-$(CONFIG_PCI_MSI) += msi.o | 29 | |
30 | msiobj-y := msi.o msi-apic.o | ||
31 | msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o | ||
32 | msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o | ||
33 | obj-$(CONFIG_PCI_MSI) += $(msiobj-y) | ||
30 | 34 | ||
31 | # | 35 | # |
32 | # ACPI Related PCI FW Functions | 36 | # ACPI Related PCI FW Functions |
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index eed67d9e73bc..723092682023 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c | |||
@@ -81,9 +81,9 @@ void __devinit pci_bus_add_device(struct pci_dev *dev) | |||
81 | { | 81 | { |
82 | device_add(&dev->dev); | 82 | device_add(&dev->dev); |
83 | 83 | ||
84 | spin_lock(&pci_bus_lock); | 84 | down_write(&pci_bus_sem); |
85 | list_add_tail(&dev->global_list, &pci_devices); | 85 | list_add_tail(&dev->global_list, &pci_devices); |
86 | spin_unlock(&pci_bus_lock); | 86 | up_write(&pci_bus_sem); |
87 | 87 | ||
88 | pci_proc_attach_device(dev); | 88 | pci_proc_attach_device(dev); |
89 | pci_create_sysfs_dev_files(dev); | 89 | pci_create_sysfs_dev_files(dev); |
@@ -125,10 +125,10 @@ void __devinit pci_bus_add_devices(struct pci_bus *bus) | |||
125 | */ | 125 | */ |
126 | if (dev->subordinate) { | 126 | if (dev->subordinate) { |
127 | if (list_empty(&dev->subordinate->node)) { | 127 | if (list_empty(&dev->subordinate->node)) { |
128 | spin_lock(&pci_bus_lock); | 128 | down_write(&pci_bus_sem); |
129 | list_add_tail(&dev->subordinate->node, | 129 | list_add_tail(&dev->subordinate->node, |
130 | &dev->bus->children); | 130 | &dev->bus->children); |
131 | spin_unlock(&pci_bus_lock); | 131 | up_write(&pci_bus_sem); |
132 | } | 132 | } |
133 | pci_bus_add_devices(dev->subordinate); | 133 | pci_bus_add_devices(dev->subordinate); |
134 | 134 | ||
@@ -168,7 +168,7 @@ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), | |||
168 | struct list_head *next; | 168 | struct list_head *next; |
169 | 169 | ||
170 | bus = top; | 170 | bus = top; |
171 | spin_lock(&pci_bus_lock); | 171 | down_read(&pci_bus_sem); |
172 | next = top->devices.next; | 172 | next = top->devices.next; |
173 | for (;;) { | 173 | for (;;) { |
174 | if (next == &bus->devices) { | 174 | if (next == &bus->devices) { |
@@ -180,22 +180,19 @@ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), | |||
180 | continue; | 180 | continue; |
181 | } | 181 | } |
182 | dev = list_entry(next, struct pci_dev, bus_list); | 182 | dev = list_entry(next, struct pci_dev, bus_list); |
183 | pci_dev_get(dev); | ||
184 | if (dev->subordinate) { | 183 | if (dev->subordinate) { |
185 | /* this is a pci-pci bridge, do its devices next */ | 184 | /* this is a pci-pci bridge, do its devices next */ |
186 | next = dev->subordinate->devices.next; | 185 | next = dev->subordinate->devices.next; |
187 | bus = dev->subordinate; | 186 | bus = dev->subordinate; |
188 | } else | 187 | } else |
189 | next = dev->bus_list.next; | 188 | next = dev->bus_list.next; |
190 | spin_unlock(&pci_bus_lock); | ||
191 | 189 | ||
192 | /* Run device routines with the bus unlocked */ | 190 | /* Run device routines with the device locked */ |
191 | down(&dev->dev.sem); | ||
193 | cb(dev, userdata); | 192 | cb(dev, userdata); |
194 | 193 | up(&dev->dev.sem); | |
195 | spin_lock(&pci_bus_lock); | ||
196 | pci_dev_put(dev); | ||
197 | } | 194 | } |
198 | spin_unlock(&pci_bus_lock); | 195 | up_read(&pci_bus_sem); |
199 | } | 196 | } |
200 | EXPORT_SYMBOL_GPL(pci_walk_bus); | 197 | EXPORT_SYMBOL_GPL(pci_walk_bus); |
201 | 198 | ||
diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index 39af9c325f35..51cb9f817c22 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c | |||
@@ -25,6 +25,7 @@ | |||
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
28 | #include <linux/moduleparam.h> | ||
28 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
29 | #include <linux/types.h> | 30 | #include <linux/types.h> |
30 | #include <linux/pci.h> | 31 | #include <linux/pci.h> |
@@ -33,10 +34,184 @@ | |||
33 | #include <acpi/actypes.h> | 34 | #include <acpi/actypes.h> |
34 | #include "pci_hotplug.h" | 35 | #include "pci_hotplug.h" |
35 | 36 | ||
37 | #define MY_NAME "acpi_pcihp" | ||
38 | |||
39 | #define dbg(fmt, arg...) do { if (debug_acpi) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __FUNCTION__ , ## arg); } while (0) | ||
40 | #define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) | ||
41 | #define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) | ||
42 | #define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) | ||
43 | |||
36 | #define METHOD_NAME__SUN "_SUN" | 44 | #define METHOD_NAME__SUN "_SUN" |
37 | #define METHOD_NAME__HPP "_HPP" | 45 | #define METHOD_NAME__HPP "_HPP" |
38 | #define METHOD_NAME_OSHP "OSHP" | 46 | #define METHOD_NAME_OSHP "OSHP" |
39 | 47 | ||
48 | static int debug_acpi; | ||
49 | |||
50 | static acpi_status | ||
51 | decode_type0_hpx_record(union acpi_object *record, struct hotplug_params *hpx) | ||
52 | { | ||
53 | int i; | ||
54 | union acpi_object *fields = record->package.elements; | ||
55 | u32 revision = fields[1].integer.value; | ||
56 | |||
57 | switch (revision) { | ||
58 | case 1: | ||
59 | if (record->package.count != 6) | ||
60 | return AE_ERROR; | ||
61 | for (i = 2; i < 6; i++) | ||
62 | if (fields[i].type != ACPI_TYPE_INTEGER) | ||
63 | return AE_ERROR; | ||
64 | hpx->t0 = &hpx->type0_data; | ||
65 | hpx->t0->revision = revision; | ||
66 | hpx->t0->cache_line_size = fields[2].integer.value; | ||
67 | hpx->t0->latency_timer = fields[3].integer.value; | ||
68 | hpx->t0->enable_serr = fields[4].integer.value; | ||
69 | hpx->t0->enable_perr = fields[5].integer.value; | ||
70 | break; | ||
71 | default: | ||
72 | printk(KERN_WARNING | ||
73 | "%s: Type 0 Revision %d record not supported\n", | ||
74 | __FUNCTION__, revision); | ||
75 | return AE_ERROR; | ||
76 | } | ||
77 | return AE_OK; | ||
78 | } | ||
79 | |||
80 | static acpi_status | ||
81 | decode_type1_hpx_record(union acpi_object *record, struct hotplug_params *hpx) | ||
82 | { | ||
83 | int i; | ||
84 | union acpi_object *fields = record->package.elements; | ||
85 | u32 revision = fields[1].integer.value; | ||
86 | |||
87 | switch (revision) { | ||
88 | case 1: | ||
89 | if (record->package.count != 5) | ||
90 | return AE_ERROR; | ||
91 | for (i = 2; i < 5; i++) | ||
92 | if (fields[i].type != ACPI_TYPE_INTEGER) | ||
93 | return AE_ERROR; | ||
94 | hpx->t1 = &hpx->type1_data; | ||
95 | hpx->t1->revision = revision; | ||
96 | hpx->t1->max_mem_read = fields[2].integer.value; | ||
97 | hpx->t1->avg_max_split = fields[3].integer.value; | ||
98 | hpx->t1->tot_max_split = fields[4].integer.value; | ||
99 | break; | ||
100 | default: | ||
101 | printk(KERN_WARNING | ||
102 | "%s: Type 1 Revision %d record not supported\n", | ||
103 | __FUNCTION__, revision); | ||
104 | return AE_ERROR; | ||
105 | } | ||
106 | return AE_OK; | ||
107 | } | ||
108 | |||
109 | static acpi_status | ||
110 | decode_type2_hpx_record(union acpi_object *record, struct hotplug_params *hpx) | ||
111 | { | ||
112 | int i; | ||
113 | union acpi_object *fields = record->package.elements; | ||
114 | u32 revision = fields[1].integer.value; | ||
115 | |||
116 | switch (revision) { | ||
117 | case 1: | ||
118 | if (record->package.count != 18) | ||
119 | return AE_ERROR; | ||
120 | for (i = 2; i < 18; i++) | ||
121 | if (fields[i].type != ACPI_TYPE_INTEGER) | ||
122 | return AE_ERROR; | ||
123 | hpx->t2 = &hpx->type2_data; | ||
124 | hpx->t2->revision = revision; | ||
125 | hpx->t2->unc_err_mask_and = fields[2].integer.value; | ||
126 | hpx->t2->unc_err_mask_or = fields[3].integer.value; | ||
127 | hpx->t2->unc_err_sever_and = fields[4].integer.value; | ||
128 | hpx->t2->unc_err_sever_or = fields[5].integer.value; | ||
129 | hpx->t2->cor_err_mask_and = fields[6].integer.value; | ||
130 | hpx->t2->cor_err_mask_or = fields[7].integer.value; | ||
131 | hpx->t2->adv_err_cap_and = fields[8].integer.value; | ||
132 | hpx->t2->adv_err_cap_or = fields[9].integer.value; | ||
133 | hpx->t2->pci_exp_devctl_and = fields[10].integer.value; | ||
134 | hpx->t2->pci_exp_devctl_or = fields[11].integer.value; | ||
135 | hpx->t2->pci_exp_lnkctl_and = fields[12].integer.value; | ||
136 | hpx->t2->pci_exp_lnkctl_or = fields[13].integer.value; | ||
137 | hpx->t2->sec_unc_err_sever_and = fields[14].integer.value; | ||
138 | hpx->t2->sec_unc_err_sever_or = fields[15].integer.value; | ||
139 | hpx->t2->sec_unc_err_mask_and = fields[16].integer.value; | ||
140 | hpx->t2->sec_unc_err_mask_or = fields[17].integer.value; | ||
141 | break; | ||
142 | default: | ||
143 | printk(KERN_WARNING | ||
144 | "%s: Type 2 Revision %d record not supported\n", | ||
145 | __FUNCTION__, revision); | ||
146 | return AE_ERROR; | ||
147 | } | ||
148 | return AE_OK; | ||
149 | } | ||
150 | |||
151 | static acpi_status | ||
152 | acpi_run_hpx(acpi_handle handle, struct hotplug_params *hpx) | ||
153 | { | ||
154 | acpi_status status; | ||
155 | struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; | ||
156 | union acpi_object *package, *record, *fields; | ||
157 | u32 type; | ||
158 | int i; | ||
159 | |||
160 | /* Clear the return buffer with zeros */ | ||
161 | memset(hpx, 0, sizeof(struct hotplug_params)); | ||
162 | |||
163 | status = acpi_evaluate_object(handle, "_HPX", NULL, &buffer); | ||
164 | if (ACPI_FAILURE(status)) | ||
165 | return status; | ||
166 | |||
167 | package = (union acpi_object *)buffer.pointer; | ||
168 | if (package->type != ACPI_TYPE_PACKAGE) { | ||
169 | status = AE_ERROR; | ||
170 | goto exit; | ||
171 | } | ||
172 | |||
173 | for (i = 0; i < package->package.count; i++) { | ||
174 | record = &package->package.elements[i]; | ||
175 | if (record->type != ACPI_TYPE_PACKAGE) { | ||
176 | status = AE_ERROR; | ||
177 | goto exit; | ||
178 | } | ||
179 | |||
180 | fields = record->package.elements; | ||
181 | if (fields[0].type != ACPI_TYPE_INTEGER || | ||
182 | fields[1].type != ACPI_TYPE_INTEGER) { | ||
183 | status = AE_ERROR; | ||
184 | goto exit; | ||
185 | } | ||
186 | |||
187 | type = fields[0].integer.value; | ||
188 | switch (type) { | ||
189 | case 0: | ||
190 | status = decode_type0_hpx_record(record, hpx); | ||
191 | if (ACPI_FAILURE(status)) | ||
192 | goto exit; | ||
193 | break; | ||
194 | case 1: | ||
195 | status = decode_type1_hpx_record(record, hpx); | ||
196 | if (ACPI_FAILURE(status)) | ||
197 | goto exit; | ||
198 | break; | ||
199 | case 2: | ||
200 | status = decode_type2_hpx_record(record, hpx); | ||
201 | if (ACPI_FAILURE(status)) | ||
202 | goto exit; | ||
203 | break; | ||
204 | default: | ||
205 | printk(KERN_ERR "%s: Type %d record not supported\n", | ||
206 | __FUNCTION__, type); | ||
207 | status = AE_ERROR; | ||
208 | goto exit; | ||
209 | } | ||
210 | } | ||
211 | exit: | ||
212 | kfree(buffer.pointer); | ||
213 | return status; | ||
214 | } | ||
40 | 215 | ||
41 | static acpi_status | 216 | static acpi_status |
42 | acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) | 217 | acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) |
@@ -50,6 +225,9 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) | |||
50 | 225 | ||
51 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &string); | 226 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &string); |
52 | 227 | ||
228 | /* Clear the return buffer with zeros */ | ||
229 | memset(hpp, 0, sizeof(struct hotplug_params)); | ||
230 | |||
53 | /* get _hpp */ | 231 | /* get _hpp */ |
54 | status = acpi_evaluate_object(handle, METHOD_NAME__HPP, NULL, &ret_buf); | 232 | status = acpi_evaluate_object(handle, METHOD_NAME__HPP, NULL, &ret_buf); |
55 | switch (status) { | 233 | switch (status) { |
@@ -58,7 +236,7 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) | |||
58 | if (!ret_buf.pointer) { | 236 | if (!ret_buf.pointer) { |
59 | printk(KERN_ERR "%s:%s alloc for _HPP fail\n", | 237 | printk(KERN_ERR "%s:%s alloc for _HPP fail\n", |
60 | __FUNCTION__, (char *)string.pointer); | 238 | __FUNCTION__, (char *)string.pointer); |
61 | acpi_os_free(string.pointer); | 239 | kfree(string.pointer); |
62 | return AE_NO_MEMORY; | 240 | return AE_NO_MEMORY; |
63 | } | 241 | } |
64 | status = acpi_evaluate_object(handle, METHOD_NAME__HPP, | 242 | status = acpi_evaluate_object(handle, METHOD_NAME__HPP, |
@@ -69,7 +247,7 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) | |||
69 | if (ACPI_FAILURE(status)) { | 247 | if (ACPI_FAILURE(status)) { |
70 | pr_debug("%s:%s _HPP fail=0x%x\n", __FUNCTION__, | 248 | pr_debug("%s:%s _HPP fail=0x%x\n", __FUNCTION__, |
71 | (char *)string.pointer, status); | 249 | (char *)string.pointer, status); |
72 | acpi_os_free(string.pointer); | 250 | kfree(string.pointer); |
73 | return status; | 251 | return status; |
74 | } | 252 | } |
75 | } | 253 | } |
@@ -98,19 +276,20 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) | |||
98 | } | 276 | } |
99 | } | 277 | } |
100 | 278 | ||
101 | hpp->cache_line_size = nui[0]; | 279 | hpp->t0 = &hpp->type0_data; |
102 | hpp->latency_timer = nui[1]; | 280 | hpp->t0->cache_line_size = nui[0]; |
103 | hpp->enable_serr = nui[2]; | 281 | hpp->t0->latency_timer = nui[1]; |
104 | hpp->enable_perr = nui[3]; | 282 | hpp->t0->enable_serr = nui[2]; |
283 | hpp->t0->enable_perr = nui[3]; | ||
105 | 284 | ||
106 | pr_debug(" _HPP: cache_line_size=0x%x\n", hpp->cache_line_size); | 285 | pr_debug(" _HPP: cache_line_size=0x%x\n", hpp->t0->cache_line_size); |
107 | pr_debug(" _HPP: latency timer =0x%x\n", hpp->latency_timer); | 286 | pr_debug(" _HPP: latency timer =0x%x\n", hpp->t0->latency_timer); |
108 | pr_debug(" _HPP: enable SERR =0x%x\n", hpp->enable_serr); | 287 | pr_debug(" _HPP: enable SERR =0x%x\n", hpp->t0->enable_serr); |
109 | pr_debug(" _HPP: enable PERR =0x%x\n", hpp->enable_perr); | 288 | pr_debug(" _HPP: enable PERR =0x%x\n", hpp->t0->enable_perr); |
110 | 289 | ||
111 | free_and_return: | 290 | free_and_return: |
112 | acpi_os_free(string.pointer); | 291 | kfree(string.pointer); |
113 | acpi_os_free(ret_buf.pointer); | 292 | kfree(ret_buf.pointer); |
114 | return status; | 293 | return status; |
115 | } | 294 | } |
116 | 295 | ||
@@ -130,13 +309,17 @@ acpi_status acpi_run_oshp(acpi_handle handle) | |||
130 | /* run OSHP */ | 309 | /* run OSHP */ |
131 | status = acpi_evaluate_object(handle, METHOD_NAME_OSHP, NULL, NULL); | 310 | status = acpi_evaluate_object(handle, METHOD_NAME_OSHP, NULL, NULL); |
132 | if (ACPI_FAILURE(status)) | 311 | if (ACPI_FAILURE(status)) |
133 | printk(KERN_ERR "%s:%s OSHP fails=0x%x\n", __FUNCTION__, | 312 | if (status != AE_NOT_FOUND) |
134 | (char *)string.pointer, status); | 313 | printk(KERN_ERR "%s:%s OSHP fails=0x%x\n", |
314 | __FUNCTION__, (char *)string.pointer, status); | ||
315 | else | ||
316 | dbg("%s:%s OSHP not found\n", | ||
317 | __FUNCTION__, (char *)string.pointer); | ||
135 | else | 318 | else |
136 | pr_debug("%s:%s OSHP passes\n", __FUNCTION__, | 319 | pr_debug("%s:%s OSHP passes\n", __FUNCTION__, |
137 | (char *)string.pointer); | 320 | (char *)string.pointer); |
138 | 321 | ||
139 | acpi_os_free(string.pointer); | 322 | kfree(string.pointer); |
140 | return status; | 323 | return status; |
141 | } | 324 | } |
142 | EXPORT_SYMBOL_GPL(acpi_run_oshp); | 325 | EXPORT_SYMBOL_GPL(acpi_run_oshp); |
@@ -145,14 +328,27 @@ EXPORT_SYMBOL_GPL(acpi_run_oshp); | |||
145 | 328 | ||
146 | /* acpi_get_hp_params_from_firmware | 329 | /* acpi_get_hp_params_from_firmware |
147 | * | 330 | * |
148 | * @dev - the pci_dev of the newly added device | 331 | * @bus - the pci_bus of the bus on which the device is newly added |
149 | * @hpp - allocated by the caller | 332 | * @hpp - allocated by the caller |
150 | */ | 333 | */ |
151 | acpi_status acpi_get_hp_params_from_firmware(struct pci_dev *dev, | 334 | acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus, |
152 | struct hotplug_params *hpp) | 335 | struct hotplug_params *hpp) |
153 | { | 336 | { |
154 | acpi_status status = AE_NOT_FOUND; | 337 | acpi_status status = AE_NOT_FOUND; |
155 | struct pci_dev *pdev = dev; | 338 | acpi_handle handle, phandle; |
339 | struct pci_bus *pbus = bus; | ||
340 | struct pci_dev *pdev; | ||
341 | |||
342 | do { | ||
343 | pdev = pbus->self; | ||
344 | if (!pdev) { | ||
345 | handle = acpi_get_pci_rootbridge_handle( | ||
346 | pci_domain_nr(pbus), pbus->number); | ||
347 | break; | ||
348 | } | ||
349 | handle = DEVICE_ACPI_HANDLE(&(pdev->dev)); | ||
350 | pbus = pbus->parent; | ||
351 | } while (!handle); | ||
156 | 352 | ||
157 | /* | 353 | /* |
158 | * _HPP settings apply to all child buses, until another _HPP is | 354 | * _HPP settings apply to all child buses, until another _HPP is |
@@ -160,15 +356,19 @@ acpi_status acpi_get_hp_params_from_firmware(struct pci_dev *dev, | |||
160 | * look for it in the parent device scope since that would apply to | 356 | * look for it in the parent device scope since that would apply to |
161 | * this pci dev. If we don't find any _HPP, use hardcoded defaults | 357 | * this pci dev. If we don't find any _HPP, use hardcoded defaults |
162 | */ | 358 | */ |
163 | while (pdev && (ACPI_FAILURE(status))) { | 359 | while (handle) { |
164 | acpi_handle handle = DEVICE_ACPI_HANDLE(&(pdev->dev)); | 360 | status = acpi_run_hpx(handle, hpp); |
165 | if (!handle) | 361 | if (ACPI_SUCCESS(status)) |
166 | break; | 362 | break; |
167 | status = acpi_run_hpp(handle, hpp); | 363 | status = acpi_run_hpp(handle, hpp); |
168 | if (!(pdev->bus->parent)) | 364 | if (ACPI_SUCCESS(status)) |
169 | break; | 365 | break; |
170 | /* Check if a parent object supports _HPP */ | 366 | if (acpi_root_bridge(handle)) |
171 | pdev = pdev->bus->parent->self; | 367 | break; |
368 | status = acpi_get_parent(handle, &phandle); | ||
369 | if (ACPI_FAILURE(status)) | ||
370 | break; | ||
371 | handle = phandle; | ||
172 | } | 372 | } |
173 | return status; | 373 | return status; |
174 | } | 374 | } |
@@ -192,20 +392,23 @@ int acpi_root_bridge(acpi_handle handle) | |||
192 | if ((info->valid & ACPI_VALID_HID) && | 392 | if ((info->valid & ACPI_VALID_HID) && |
193 | !strcmp(PCI_ROOT_HID_STRING, | 393 | !strcmp(PCI_ROOT_HID_STRING, |
194 | info->hardware_id.value)) { | 394 | info->hardware_id.value)) { |
195 | acpi_os_free(buffer.pointer); | 395 | kfree(buffer.pointer); |
196 | return 1; | 396 | return 1; |
197 | } | 397 | } |
198 | if (info->valid & ACPI_VALID_CID) { | 398 | if (info->valid & ACPI_VALID_CID) { |
199 | for (i=0; i < info->compatibility_id.count; i++) { | 399 | for (i=0; i < info->compatibility_id.count; i++) { |
200 | if (!strcmp(PCI_ROOT_HID_STRING, | 400 | if (!strcmp(PCI_ROOT_HID_STRING, |
201 | info->compatibility_id.id[i].value)) { | 401 | info->compatibility_id.id[i].value)) { |
202 | acpi_os_free(buffer.pointer); | 402 | kfree(buffer.pointer); |
203 | return 1; | 403 | return 1; |
204 | } | 404 | } |
205 | } | 405 | } |
206 | } | 406 | } |
207 | acpi_os_free(buffer.pointer); | 407 | kfree(buffer.pointer); |
208 | } | 408 | } |
209 | return 0; | 409 | return 0; |
210 | } | 410 | } |
211 | EXPORT_SYMBOL_GPL(acpi_root_bridge); | 411 | EXPORT_SYMBOL_GPL(acpi_root_bridge); |
412 | |||
413 | module_param(debug_acpi, bool, 0644); | ||
414 | MODULE_PARM_DESC(debug_acpi, "Debugging mode for ACPI enabled or not"); | ||
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 467ac70a46ff..17a93f890dba 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h | |||
@@ -75,6 +75,10 @@ struct acpiphp_bridge { | |||
75 | struct list_head list; | 75 | struct list_head list; |
76 | acpi_handle handle; | 76 | acpi_handle handle; |
77 | struct acpiphp_slot *slots; | 77 | struct acpiphp_slot *slots; |
78 | |||
79 | /* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */ | ||
80 | struct acpiphp_func *func; | ||
81 | |||
78 | int type; | 82 | int type; |
79 | int nr_slots; | 83 | int nr_slots; |
80 | 84 | ||
@@ -122,6 +126,7 @@ struct acpiphp_slot { | |||
122 | */ | 126 | */ |
123 | struct acpiphp_func { | 127 | struct acpiphp_func { |
124 | struct acpiphp_slot *slot; /* parent */ | 128 | struct acpiphp_slot *slot; /* parent */ |
129 | struct acpiphp_bridge *bridge; /* Ejectable PCI-to-PCI bridge */ | ||
125 | 130 | ||
126 | struct list_head sibling; | 131 | struct list_head sibling; |
127 | struct pci_dev *pci_dev; | 132 | struct pci_dev *pci_dev; |
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 053ee843863c..d370f999782e 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
@@ -286,13 +286,19 @@ static void decode_hpp(struct acpiphp_bridge *bridge) | |||
286 | { | 286 | { |
287 | acpi_status status; | 287 | acpi_status status; |
288 | 288 | ||
289 | status = acpi_get_hp_params_from_firmware(bridge->pci_dev, &bridge->hpp); | 289 | status = acpi_get_hp_params_from_firmware(bridge->pci_bus, &bridge->hpp); |
290 | if (ACPI_FAILURE(status)) { | 290 | if (ACPI_FAILURE(status) || |
291 | !bridge->hpp.t0 || (bridge->hpp.t0->revision > 1)) { | ||
291 | /* use default numbers */ | 292 | /* use default numbers */ |
292 | bridge->hpp.cache_line_size = 0x10; | 293 | printk(KERN_WARNING |
293 | bridge->hpp.latency_timer = 0x40; | 294 | "%s: Could not get hotplug parameters. Use defaults\n", |
294 | bridge->hpp.enable_serr = 0; | 295 | __FUNCTION__); |
295 | bridge->hpp.enable_perr = 0; | 296 | bridge->hpp.t0 = &bridge->hpp.type0_data; |
297 | bridge->hpp.t0->revision = 0; | ||
298 | bridge->hpp.t0->cache_line_size = 0x10; | ||
299 | bridge->hpp.t0->latency_timer = 0x40; | ||
300 | bridge->hpp.t0->enable_serr = 0; | ||
301 | bridge->hpp.t0->enable_perr = 0; | ||
296 | } | 302 | } |
297 | } | 303 | } |
298 | 304 | ||
@@ -319,6 +325,13 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge) | |||
319 | 325 | ||
320 | /* install notify handler */ | 326 | /* install notify handler */ |
321 | if (bridge->type != BRIDGE_TYPE_HOST) { | 327 | if (bridge->type != BRIDGE_TYPE_HOST) { |
328 | if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) { | ||
329 | status = acpi_remove_notify_handler(bridge->func->handle, | ||
330 | ACPI_SYSTEM_NOTIFY, | ||
331 | handle_hotplug_event_func); | ||
332 | if (ACPI_FAILURE(status)) | ||
333 | err("failed to remove notify handler\n"); | ||
334 | } | ||
322 | status = acpi_install_notify_handler(bridge->handle, | 335 | status = acpi_install_notify_handler(bridge->handle, |
323 | ACPI_SYSTEM_NOTIFY, | 336 | ACPI_SYSTEM_NOTIFY, |
324 | handle_hotplug_event_bridge, | 337 | handle_hotplug_event_bridge, |
@@ -331,6 +344,66 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge) | |||
331 | } | 344 | } |
332 | 345 | ||
333 | 346 | ||
347 | /* find acpiphp_func from acpiphp_bridge */ | ||
348 | static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle) | ||
349 | { | ||
350 | struct list_head *node, *l; | ||
351 | struct acpiphp_bridge *bridge; | ||
352 | struct acpiphp_slot *slot; | ||
353 | struct acpiphp_func *func; | ||
354 | |||
355 | list_for_each(node, &bridge_list) { | ||
356 | bridge = list_entry(node, struct acpiphp_bridge, list); | ||
357 | for (slot = bridge->slots; slot; slot = slot->next) { | ||
358 | list_for_each(l, &slot->funcs) { | ||
359 | func = list_entry(l, struct acpiphp_func, | ||
360 | sibling); | ||
361 | if (func->handle == handle) | ||
362 | return func; | ||
363 | } | ||
364 | } | ||
365 | } | ||
366 | |||
367 | return NULL; | ||
368 | } | ||
369 | |||
370 | |||
371 | static inline void config_p2p_bridge_flags(struct acpiphp_bridge *bridge) | ||
372 | { | ||
373 | acpi_handle dummy_handle; | ||
374 | |||
375 | if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, | ||
376 | "_STA", &dummy_handle))) | ||
377 | bridge->flags |= BRIDGE_HAS_STA; | ||
378 | |||
379 | if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, | ||
380 | "_EJ0", &dummy_handle))) | ||
381 | bridge->flags |= BRIDGE_HAS_EJ0; | ||
382 | |||
383 | if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, | ||
384 | "_PS0", &dummy_handle))) | ||
385 | bridge->flags |= BRIDGE_HAS_PS0; | ||
386 | |||
387 | if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, | ||
388 | "_PS3", &dummy_handle))) | ||
389 | bridge->flags |= BRIDGE_HAS_PS3; | ||
390 | |||
391 | /* is this ejectable p2p bridge? */ | ||
392 | if (bridge->flags & BRIDGE_HAS_EJ0) { | ||
393 | struct acpiphp_func *func; | ||
394 | |||
395 | dbg("found ejectable p2p bridge\n"); | ||
396 | |||
397 | /* make link between PCI bridge and PCI function */ | ||
398 | func = acpiphp_bridge_handle_to_function(bridge->handle); | ||
399 | if (!func) | ||
400 | return; | ||
401 | bridge->func = func; | ||
402 | func->bridge = bridge; | ||
403 | } | ||
404 | } | ||
405 | |||
406 | |||
334 | /* allocate and initialize host bridge data structure */ | 407 | /* allocate and initialize host bridge data structure */ |
335 | static void add_host_bridge(acpi_handle *handle, struct pci_bus *pci_bus) | 408 | static void add_host_bridge(acpi_handle *handle, struct pci_bus *pci_bus) |
336 | { | 409 | { |
@@ -364,6 +437,7 @@ static void add_p2p_bridge(acpi_handle *handle, struct pci_dev *pci_dev) | |||
364 | 437 | ||
365 | bridge->type = BRIDGE_TYPE_P2P; | 438 | bridge->type = BRIDGE_TYPE_P2P; |
366 | bridge->handle = handle; | 439 | bridge->handle = handle; |
440 | config_p2p_bridge_flags(bridge); | ||
367 | 441 | ||
368 | bridge->pci_dev = pci_dev_get(pci_dev); | 442 | bridge->pci_dev = pci_dev_get(pci_dev); |
369 | bridge->pci_bus = pci_dev->subordinate; | 443 | bridge->pci_bus = pci_dev->subordinate; |
@@ -423,7 +497,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
423 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, | 497 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, |
424 | find_p2p_bridge, dev->subordinate, NULL); | 498 | find_p2p_bridge, dev->subordinate, NULL); |
425 | if (ACPI_FAILURE(status)) | 499 | if (ACPI_FAILURE(status)) |
426 | warn("find_p2p_bridge faied (error code = 0x%x)\n", status); | 500 | warn("find_p2p_bridge failed (error code = 0x%x)\n", status); |
427 | 501 | ||
428 | out: | 502 | out: |
429 | pci_dev_put(dev); | 503 | pci_dev_put(dev); |
@@ -478,7 +552,6 @@ static int add_bridge(acpi_handle handle) | |||
478 | if (detect_ejectable_slots(handle) > 0) { | 552 | if (detect_ejectable_slots(handle) > 0) { |
479 | dbg("found PCI host-bus bridge with hot-pluggable slots\n"); | 553 | dbg("found PCI host-bus bridge with hot-pluggable slots\n"); |
480 | add_host_bridge(handle, pci_bus); | 554 | add_host_bridge(handle, pci_bus); |
481 | return 0; | ||
482 | } | 555 | } |
483 | 556 | ||
484 | /* search P2P bridges under this host bridge */ | 557 | /* search P2P bridges under this host bridge */ |
@@ -486,7 +559,7 @@ static int add_bridge(acpi_handle handle) | |||
486 | find_p2p_bridge, pci_bus, NULL); | 559 | find_p2p_bridge, pci_bus, NULL); |
487 | 560 | ||
488 | if (ACPI_FAILURE(status)) | 561 | if (ACPI_FAILURE(status)) |
489 | warn("find_p2p_bridge faied (error code = 0x%x)\n",status); | 562 | warn("find_p2p_bridge failed (error code = 0x%x)\n", status); |
490 | 563 | ||
491 | return 0; | 564 | return 0; |
492 | } | 565 | } |
@@ -516,6 +589,16 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) | |||
516 | if (ACPI_FAILURE(status)) | 589 | if (ACPI_FAILURE(status)) |
517 | err("failed to remove notify handler\n"); | 590 | err("failed to remove notify handler\n"); |
518 | 591 | ||
592 | if ((bridge->type != BRIDGE_TYPE_HOST) && | ||
593 | ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)) { | ||
594 | status = acpi_install_notify_handler(bridge->func->handle, | ||
595 | ACPI_SYSTEM_NOTIFY, | ||
596 | handle_hotplug_event_func, | ||
597 | bridge->func); | ||
598 | if (ACPI_FAILURE(status)) | ||
599 | err("failed to install interrupt notify handler\n"); | ||
600 | } | ||
601 | |||
519 | slot = bridge->slots; | 602 | slot = bridge->slots; |
520 | while (slot) { | 603 | while (slot) { |
521 | struct acpiphp_slot *next = slot->next; | 604 | struct acpiphp_slot *next = slot->next; |
@@ -549,6 +632,11 @@ cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
549 | { | 632 | { |
550 | struct acpiphp_bridge *bridge; | 633 | struct acpiphp_bridge *bridge; |
551 | 634 | ||
635 | /* cleanup p2p bridges under this P2P bridge | ||
636 | in a depth-first manner */ | ||
637 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, | ||
638 | cleanup_p2p_bridge, NULL, NULL); | ||
639 | |||
552 | if (!(bridge = acpiphp_handle_to_bridge(handle))) | 640 | if (!(bridge = acpiphp_handle_to_bridge(handle))) |
553 | return AE_OK; | 641 | return AE_OK; |
554 | cleanup_bridge(bridge); | 642 | cleanup_bridge(bridge); |
@@ -559,15 +647,14 @@ static void remove_bridge(acpi_handle handle) | |||
559 | { | 647 | { |
560 | struct acpiphp_bridge *bridge; | 648 | struct acpiphp_bridge *bridge; |
561 | 649 | ||
650 | /* cleanup p2p bridges under this host bridge | ||
651 | in a depth-first manner */ | ||
652 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, | ||
653 | (u32)1, cleanup_p2p_bridge, NULL, NULL); | ||
654 | |||
562 | bridge = acpiphp_handle_to_bridge(handle); | 655 | bridge = acpiphp_handle_to_bridge(handle); |
563 | if (bridge) { | 656 | if (bridge) |
564 | cleanup_bridge(bridge); | 657 | cleanup_bridge(bridge); |
565 | } else { | ||
566 | /* clean-up p2p bridges under this host bridge */ | ||
567 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, | ||
568 | ACPI_UINT32_MAX, cleanup_p2p_bridge, | ||
569 | NULL, NULL); | ||
570 | } | ||
571 | } | 658 | } |
572 | 659 | ||
573 | static struct pci_dev * get_apic_pci_info(acpi_handle handle) | 660 | static struct pci_dev * get_apic_pci_info(acpi_handle handle) |
@@ -634,7 +721,7 @@ static int get_gsi_base(acpi_handle handle, u32 *gsi_base) | |||
634 | break; | 721 | break; |
635 | } | 722 | } |
636 | out: | 723 | out: |
637 | acpi_os_free(buffer.pointer); | 724 | kfree(buffer.pointer); |
638 | return result; | 725 | return result; |
639 | } | 726 | } |
640 | 727 | ||
@@ -797,36 +884,6 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus) | |||
797 | } | 884 | } |
798 | 885 | ||
799 | 886 | ||
800 | |||
801 | /** | ||
802 | * get_func - get a pointer to acpiphp_func given a slot, device | ||
803 | * @slot: slot to search | ||
804 | * @dev: pci_dev struct to match. | ||
805 | * | ||
806 | * This function will increase the reference count of pci_dev, | ||
807 | * so callers should call pci_dev_put when complete. | ||
808 | * | ||
809 | */ | ||
810 | static struct acpiphp_func * | ||
811 | get_func(struct acpiphp_slot *slot, struct pci_dev *dev) | ||
812 | { | ||
813 | struct acpiphp_func *func = NULL; | ||
814 | struct pci_bus *bus = slot->bridge->pci_bus; | ||
815 | struct pci_dev *pdev; | ||
816 | |||
817 | list_for_each_entry(func, &slot->funcs, sibling) { | ||
818 | pdev = pci_get_slot(bus, PCI_DEVFN(slot->device, | ||
819 | func->function)); | ||
820 | if (pdev) { | ||
821 | if (pdev == dev) | ||
822 | break; | ||
823 | pci_dev_put(pdev); | ||
824 | } | ||
825 | } | ||
826 | return func; | ||
827 | } | ||
828 | |||
829 | |||
830 | /** | 887 | /** |
831 | * acpiphp_bus_add - add a new bus to acpi subsystem | 888 | * acpiphp_bus_add - add a new bus to acpi subsystem |
832 | * @func: acpiphp_func of the bridge | 889 | * @func: acpiphp_func of the bridge |
@@ -872,6 +929,28 @@ acpiphp_bus_add_out: | |||
872 | } | 929 | } |
873 | 930 | ||
874 | 931 | ||
932 | /** | ||
933 | * acpiphp_bus_trim - trim a bus from acpi subsystem | ||
934 | * @handle: handle to acpi namespace | ||
935 | * | ||
936 | */ | ||
937 | int acpiphp_bus_trim(acpi_handle handle) | ||
938 | { | ||
939 | struct acpi_device *device; | ||
940 | int retval; | ||
941 | |||
942 | retval = acpi_bus_get_device(handle, &device); | ||
943 | if (retval) { | ||
944 | dbg("acpi_device not found\n"); | ||
945 | return retval; | ||
946 | } | ||
947 | |||
948 | retval = acpi_bus_trim(device, 1); | ||
949 | if (retval) | ||
950 | err("cannot remove from acpi list\n"); | ||
951 | |||
952 | return retval; | ||
953 | } | ||
875 | 954 | ||
876 | /** | 955 | /** |
877 | * enable_device - enable, configure a slot | 956 | * enable_device - enable, configure a slot |
@@ -889,6 +968,7 @@ static int enable_device(struct acpiphp_slot *slot) | |||
889 | struct acpiphp_func *func; | 968 | struct acpiphp_func *func; |
890 | int retval = 0; | 969 | int retval = 0; |
891 | int num, max, pass; | 970 | int num, max, pass; |
971 | acpi_status status; | ||
892 | 972 | ||
893 | if (slot->flags & SLOT_ENABLED) | 973 | if (slot->flags & SLOT_ENABLED) |
894 | goto err_exit; | 974 | goto err_exit; |
@@ -918,19 +998,17 @@ static int enable_device(struct acpiphp_slot *slot) | |||
918 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || | 998 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || |
919 | dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { | 999 | dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { |
920 | max = pci_scan_bridge(bus, dev, max, pass); | 1000 | max = pci_scan_bridge(bus, dev, max, pass); |
921 | if (pass && dev->subordinate) { | 1001 | if (pass && dev->subordinate) |
922 | pci_bus_size_bridges(dev->subordinate); | 1002 | pci_bus_size_bridges(dev->subordinate); |
923 | func = get_func(slot, dev); | ||
924 | if (func) { | ||
925 | acpiphp_bus_add(func); | ||
926 | /* side effect of get_func */ | ||
927 | pci_dev_put(dev); | ||
928 | } | ||
929 | } | ||
930 | } | 1003 | } |
931 | } | 1004 | } |
932 | } | 1005 | } |
933 | 1006 | ||
1007 | list_for_each (l, &slot->funcs) { | ||
1008 | func = list_entry(l, struct acpiphp_func, sibling); | ||
1009 | acpiphp_bus_add(func); | ||
1010 | } | ||
1011 | |||
934 | pci_bus_assign_resources(bus); | 1012 | pci_bus_assign_resources(bus); |
935 | acpiphp_sanitize_bus(bus); | 1013 | acpiphp_sanitize_bus(bus); |
936 | pci_enable_bridges(bus); | 1014 | pci_enable_bridges(bus); |
@@ -943,6 +1021,17 @@ static int enable_device(struct acpiphp_slot *slot) | |||
943 | func = list_entry(l, struct acpiphp_func, sibling); | 1021 | func = list_entry(l, struct acpiphp_func, sibling); |
944 | func->pci_dev = pci_get_slot(bus, PCI_DEVFN(slot->device, | 1022 | func->pci_dev = pci_get_slot(bus, PCI_DEVFN(slot->device, |
945 | func->function)); | 1023 | func->function)); |
1024 | if (!func->pci_dev) | ||
1025 | continue; | ||
1026 | |||
1027 | if (func->pci_dev->hdr_type != PCI_HEADER_TYPE_BRIDGE && | ||
1028 | func->pci_dev->hdr_type != PCI_HEADER_TYPE_CARDBUS) | ||
1029 | continue; | ||
1030 | |||
1031 | status = find_p2p_bridge(func->handle, (u32)1, bus, NULL); | ||
1032 | if (ACPI_FAILURE(status)) | ||
1033 | warn("find_p2p_bridge failed (error code = 0x%x)\n", | ||
1034 | status); | ||
946 | } | 1035 | } |
947 | 1036 | ||
948 | slot->flags |= SLOT_ENABLED; | 1037 | slot->flags |= SLOT_ENABLED; |
@@ -967,6 +1056,18 @@ static int disable_device(struct acpiphp_slot *slot) | |||
967 | 1056 | ||
968 | list_for_each (l, &slot->funcs) { | 1057 | list_for_each (l, &slot->funcs) { |
969 | func = list_entry(l, struct acpiphp_func, sibling); | 1058 | func = list_entry(l, struct acpiphp_func, sibling); |
1059 | |||
1060 | if (func->bridge) { | ||
1061 | /* cleanup p2p bridges under this P2P bridge */ | ||
1062 | cleanup_p2p_bridge(func->bridge->handle, | ||
1063 | (u32)1, NULL, NULL); | ||
1064 | func->bridge = NULL; | ||
1065 | } | ||
1066 | |||
1067 | acpiphp_bus_trim(func->handle); | ||
1068 | /* try to remove anyway. | ||
1069 | * acpiphp_bus_add might have been failed */ | ||
1070 | |||
970 | if (!func->pci_dev) | 1071 | if (!func->pci_dev) |
971 | continue; | 1072 | continue; |
972 | 1073 | ||
@@ -1111,16 +1212,17 @@ static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge) | |||
1111 | (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && | 1212 | (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && |
1112 | (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) | 1213 | (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) |
1113 | return; | 1214 | return; |
1215 | |||
1114 | pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, | 1216 | pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, |
1115 | bridge->hpp.cache_line_size); | 1217 | bridge->hpp.t0->cache_line_size); |
1116 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, | 1218 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, |
1117 | bridge->hpp.latency_timer); | 1219 | bridge->hpp.t0->latency_timer); |
1118 | pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); | 1220 | pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); |
1119 | if (bridge->hpp.enable_serr) | 1221 | if (bridge->hpp.t0->enable_serr) |
1120 | pci_cmd |= PCI_COMMAND_SERR; | 1222 | pci_cmd |= PCI_COMMAND_SERR; |
1121 | else | 1223 | else |
1122 | pci_cmd &= ~PCI_COMMAND_SERR; | 1224 | pci_cmd &= ~PCI_COMMAND_SERR; |
1123 | if (bridge->hpp.enable_perr) | 1225 | if (bridge->hpp.t0->enable_perr) |
1124 | pci_cmd |= PCI_COMMAND_PARITY; | 1226 | pci_cmd |= PCI_COMMAND_PARITY; |
1125 | else | 1227 | else |
1126 | pci_cmd &= ~PCI_COMMAND_PARITY; | 1228 | pci_cmd &= ~PCI_COMMAND_PARITY; |
@@ -1129,13 +1231,13 @@ static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge) | |||
1129 | /* Program bridge control value and child devices */ | 1231 | /* Program bridge control value and child devices */ |
1130 | if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { | 1232 | if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { |
1131 | pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, | 1233 | pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, |
1132 | bridge->hpp.latency_timer); | 1234 | bridge->hpp.t0->latency_timer); |
1133 | pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); | 1235 | pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); |
1134 | if (bridge->hpp.enable_serr) | 1236 | if (bridge->hpp.t0->enable_serr) |
1135 | pci_bctl |= PCI_BRIDGE_CTL_SERR; | 1237 | pci_bctl |= PCI_BRIDGE_CTL_SERR; |
1136 | else | 1238 | else |
1137 | pci_bctl &= ~PCI_BRIDGE_CTL_SERR; | 1239 | pci_bctl &= ~PCI_BRIDGE_CTL_SERR; |
1138 | if (bridge->hpp.enable_perr) | 1240 | if (bridge->hpp.t0->enable_perr) |
1139 | pci_bctl |= PCI_BRIDGE_CTL_PARITY; | 1241 | pci_bctl |= PCI_BRIDGE_CTL_PARITY; |
1140 | else | 1242 | else |
1141 | pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; | 1243 | pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; |
@@ -1155,6 +1257,7 @@ static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus) | |||
1155 | 1257 | ||
1156 | memset(&bridge, 0, sizeof(bridge)); | 1258 | memset(&bridge, 0, sizeof(bridge)); |
1157 | bridge.handle = handle; | 1259 | bridge.handle = handle; |
1260 | bridge.pci_bus = bus; | ||
1158 | bridge.pci_dev = bus->self; | 1261 | bridge.pci_dev = bus->self; |
1159 | decode_hpp(&bridge); | 1262 | decode_hpp(&bridge); |
1160 | list_for_each_entry(dev, &bus->devices, bus_list) | 1263 | list_for_each_entry(dev, &bus->devices, bus_list) |
@@ -1297,6 +1400,13 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont | |||
1297 | case ACPI_NOTIFY_EJECT_REQUEST: | 1400 | case ACPI_NOTIFY_EJECT_REQUEST: |
1298 | /* request device eject */ | 1401 | /* request device eject */ |
1299 | dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); | 1402 | dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); |
1403 | if ((bridge->type != BRIDGE_TYPE_HOST) && | ||
1404 | (bridge->flags & BRIDGE_HAS_EJ0)) { | ||
1405 | struct acpiphp_slot *slot; | ||
1406 | slot = bridge->func->slot; | ||
1407 | if (!acpiphp_disable_slot(slot)) | ||
1408 | acpiphp_eject_slot(slot); | ||
1409 | } | ||
1300 | break; | 1410 | break; |
1301 | 1411 | ||
1302 | case ACPI_NOTIFY_FREQUENCY_MISMATCH: | 1412 | case ACPI_NOTIFY_FREQUENCY_MISMATCH: |
@@ -1490,9 +1600,15 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot) | |||
1490 | if (retval) | 1600 | if (retval) |
1491 | goto err_exit; | 1601 | goto err_exit; |
1492 | 1602 | ||
1493 | if (get_slot_status(slot) == ACPI_STA_ALL) | 1603 | if (get_slot_status(slot) == ACPI_STA_ALL) { |
1494 | /* configure all functions */ | 1604 | /* configure all functions */ |
1495 | retval = enable_device(slot); | 1605 | retval = enable_device(slot); |
1606 | if (retval) | ||
1607 | power_off_slot(slot); | ||
1608 | } else { | ||
1609 | dbg("%s: Slot status is not ACPI_STA_ALL\n", __FUNCTION__); | ||
1610 | power_off_slot(slot); | ||
1611 | } | ||
1496 | 1612 | ||
1497 | err_exit: | 1613 | err_exit: |
1498 | mutex_unlock(&slot->crit_sect); | 1614 | mutex_unlock(&slot->crit_sect); |
diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c index e13d5b87241a..59392946c2bd 100644 --- a/drivers/pci/hotplug/ibmphp_core.c +++ b/drivers/pci/hotplug/ibmphp_core.c | |||
@@ -285,7 +285,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value) | |||
285 | (ulong) hotplug_slot, (ulong) value); | 285 | (ulong) hotplug_slot, (ulong) value); |
286 | 286 | ||
287 | ibmphp_lock_operations(); | 287 | ibmphp_lock_operations(); |
288 | if (hotplug_slot && value) { | 288 | if (hotplug_slot) { |
289 | pslot = hotplug_slot->private; | 289 | pslot = hotplug_slot->private; |
290 | if (pslot) { | 290 | if (pslot) { |
291 | memcpy(&myslot, pslot, sizeof(struct slot)); | 291 | memcpy(&myslot, pslot, sizeof(struct slot)); |
@@ -315,7 +315,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value) | |||
315 | debug("get_latch_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", | 315 | debug("get_latch_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", |
316 | (ulong) hotplug_slot, (ulong) value); | 316 | (ulong) hotplug_slot, (ulong) value); |
317 | ibmphp_lock_operations(); | 317 | ibmphp_lock_operations(); |
318 | if (hotplug_slot && value) { | 318 | if (hotplug_slot) { |
319 | pslot = hotplug_slot->private; | 319 | pslot = hotplug_slot->private; |
320 | if (pslot) { | 320 | if (pslot) { |
321 | memcpy(&myslot, pslot, sizeof(struct slot)); | 321 | memcpy(&myslot, pslot, sizeof(struct slot)); |
@@ -342,7 +342,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) | |||
342 | debug("get_power_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", | 342 | debug("get_power_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", |
343 | (ulong) hotplug_slot, (ulong) value); | 343 | (ulong) hotplug_slot, (ulong) value); |
344 | ibmphp_lock_operations(); | 344 | ibmphp_lock_operations(); |
345 | if (hotplug_slot && value) { | 345 | if (hotplug_slot) { |
346 | pslot = hotplug_slot->private; | 346 | pslot = hotplug_slot->private; |
347 | if (pslot) { | 347 | if (pslot) { |
348 | memcpy(&myslot, pslot, sizeof(struct slot)); | 348 | memcpy(&myslot, pslot, sizeof(struct slot)); |
@@ -369,7 +369,7 @@ static int get_adapter_present(struct hotplug_slot *hotplug_slot, u8 * value) | |||
369 | debug("get_adapter_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", | 369 | debug("get_adapter_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", |
370 | (ulong) hotplug_slot, (ulong) value); | 370 | (ulong) hotplug_slot, (ulong) value); |
371 | ibmphp_lock_operations(); | 371 | ibmphp_lock_operations(); |
372 | if (hotplug_slot && value) { | 372 | if (hotplug_slot) { |
373 | pslot = hotplug_slot->private; | 373 | pslot = hotplug_slot->private; |
374 | if (pslot) { | 374 | if (pslot) { |
375 | memcpy(&myslot, pslot, sizeof(struct slot)); | 375 | memcpy(&myslot, pslot, sizeof(struct slot)); |
@@ -401,7 +401,7 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe | |||
401 | 401 | ||
402 | ibmphp_lock_operations(); | 402 | ibmphp_lock_operations(); |
403 | 403 | ||
404 | if (hotplug_slot && value) { | 404 | if (hotplug_slot) { |
405 | pslot = hotplug_slot->private; | 405 | pslot = hotplug_slot->private; |
406 | if (pslot) { | 406 | if (pslot) { |
407 | rc = 0; | 407 | rc = 0; |
@@ -441,7 +441,7 @@ static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe | |||
441 | 441 | ||
442 | ibmphp_lock_operations(); | 442 | ibmphp_lock_operations(); |
443 | 443 | ||
444 | if (hotplug_slot && value) { | 444 | if (hotplug_slot) { |
445 | pslot = hotplug_slot->private; | 445 | pslot = hotplug_slot->private; |
446 | if (pslot) { | 446 | if (pslot) { |
447 | rc = get_cur_bus_info(&pslot); | 447 | rc = get_cur_bus_info(&pslot); |
diff --git a/drivers/pci/hotplug/pci_hotplug.h b/drivers/pci/hotplug/pci_hotplug.h index eb0d01d47236..e929b7c11429 100644 --- a/drivers/pci/hotplug/pci_hotplug.h +++ b/drivers/pci/hotplug/pci_hotplug.h | |||
@@ -176,11 +176,51 @@ extern int pci_hp_change_slot_info (struct hotplug_slot *slot, | |||
176 | struct hotplug_slot_info *info); | 176 | struct hotplug_slot_info *info); |
177 | extern struct subsystem pci_hotplug_slots_subsys; | 177 | extern struct subsystem pci_hotplug_slots_subsys; |
178 | 178 | ||
179 | /* PCI Setting Record (Type 0) */ | ||
180 | struct hpp_type0 { | ||
181 | u32 revision; | ||
182 | u8 cache_line_size; | ||
183 | u8 latency_timer; | ||
184 | u8 enable_serr; | ||
185 | u8 enable_perr; | ||
186 | }; | ||
187 | |||
188 | /* PCI-X Setting Record (Type 1) */ | ||
189 | struct hpp_type1 { | ||
190 | u32 revision; | ||
191 | u8 max_mem_read; | ||
192 | u8 avg_max_split; | ||
193 | u16 tot_max_split; | ||
194 | }; | ||
195 | |||
196 | /* PCI Express Setting Record (Type 2) */ | ||
197 | struct hpp_type2 { | ||
198 | u32 revision; | ||
199 | u32 unc_err_mask_and; | ||
200 | u32 unc_err_mask_or; | ||
201 | u32 unc_err_sever_and; | ||
202 | u32 unc_err_sever_or; | ||
203 | u32 cor_err_mask_and; | ||
204 | u32 cor_err_mask_or; | ||
205 | u32 adv_err_cap_and; | ||
206 | u32 adv_err_cap_or; | ||
207 | u16 pci_exp_devctl_and; | ||
208 | u16 pci_exp_devctl_or; | ||
209 | u16 pci_exp_lnkctl_and; | ||
210 | u16 pci_exp_lnkctl_or; | ||
211 | u32 sec_unc_err_sever_and; | ||
212 | u32 sec_unc_err_sever_or; | ||
213 | u32 sec_unc_err_mask_and; | ||
214 | u32 sec_unc_err_mask_or; | ||
215 | }; | ||
216 | |||
179 | struct hotplug_params { | 217 | struct hotplug_params { |
180 | u8 cache_line_size; | 218 | struct hpp_type0 *t0; /* Type0: NULL if not available */ |
181 | u8 latency_timer; | 219 | struct hpp_type1 *t1; /* Type1: NULL if not available */ |
182 | u8 enable_serr; | 220 | struct hpp_type2 *t2; /* Type2: NULL if not available */ |
183 | u8 enable_perr; | 221 | struct hpp_type0 type0_data; |
222 | struct hpp_type1 type1_data; | ||
223 | struct hpp_type2 type2_data; | ||
184 | }; | 224 | }; |
185 | 225 | ||
186 | #ifdef CONFIG_ACPI | 226 | #ifdef CONFIG_ACPI |
@@ -188,7 +228,7 @@ struct hotplug_params { | |||
188 | #include <acpi/acpi_bus.h> | 228 | #include <acpi/acpi_bus.h> |
189 | #include <acpi/actypes.h> | 229 | #include <acpi/actypes.h> |
190 | extern acpi_status acpi_run_oshp(acpi_handle handle); | 230 | extern acpi_status acpi_run_oshp(acpi_handle handle); |
191 | extern acpi_status acpi_get_hp_params_from_firmware(struct pci_dev *dev, | 231 | extern acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus, |
192 | struct hotplug_params *hpp); | 232 | struct hotplug_params *hpp); |
193 | int acpi_root_bridge(acpi_handle handle); | 233 | int acpi_root_bridge(acpi_handle handle); |
194 | #endif | 234 | #endif |
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 92c1f0f1e1ad..ce89f5815861 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h | |||
@@ -284,7 +284,7 @@ struct hpc_ops { | |||
284 | static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev, | 284 | static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev, |
285 | struct hotplug_params *hpp) | 285 | struct hotplug_params *hpp) |
286 | { | 286 | { |
287 | if (ACPI_FAILURE(acpi_get_hp_params_from_firmware(dev, hpp))) | 287 | if (ACPI_FAILURE(acpi_get_hp_params_from_firmware(dev->bus, hpp))) |
288 | return -ENODEV; | 288 | return -ENODEV; |
289 | return 0; | 289 | return 0; |
290 | } | 290 | } |
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 601cf9045b20..c67b7c3f1ddf 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c | |||
@@ -69,6 +69,7 @@ static int get_power_status (struct hotplug_slot *slot, u8 *value); | |||
69 | static int get_attention_status (struct hotplug_slot *slot, u8 *value); | 69 | static int get_attention_status (struct hotplug_slot *slot, u8 *value); |
70 | static int get_latch_status (struct hotplug_slot *slot, u8 *value); | 70 | static int get_latch_status (struct hotplug_slot *slot, u8 *value); |
71 | static int get_adapter_status (struct hotplug_slot *slot, u8 *value); | 71 | static int get_adapter_status (struct hotplug_slot *slot, u8 *value); |
72 | static int get_address (struct hotplug_slot *slot, u32 *value); | ||
72 | static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); | 73 | static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); |
73 | static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); | 74 | static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); |
74 | 75 | ||
@@ -81,6 +82,7 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { | |||
81 | .get_attention_status = get_attention_status, | 82 | .get_attention_status = get_attention_status, |
82 | .get_latch_status = get_latch_status, | 83 | .get_latch_status = get_latch_status, |
83 | .get_adapter_status = get_adapter_status, | 84 | .get_adapter_status = get_adapter_status, |
85 | .get_address = get_address, | ||
84 | .get_max_bus_speed = get_max_bus_speed, | 86 | .get_max_bus_speed = get_max_bus_speed, |
85 | .get_cur_bus_speed = get_cur_bus_speed, | 87 | .get_cur_bus_speed = get_cur_bus_speed, |
86 | }; | 88 | }; |
@@ -331,6 +333,18 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) | |||
331 | return 0; | 333 | return 0; |
332 | } | 334 | } |
333 | 335 | ||
336 | static int get_address(struct hotplug_slot *hotplug_slot, u32 *value) | ||
337 | { | ||
338 | struct slot *slot = hotplug_slot->private; | ||
339 | struct pci_bus *bus = slot->ctrl->pci_dev->subordinate; | ||
340 | |||
341 | dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); | ||
342 | |||
343 | *value = (pci_domain_nr(bus) << 16) | (slot->bus << 8) | slot->device; | ||
344 | |||
345 | return 0; | ||
346 | } | ||
347 | |||
334 | static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) | 348 | static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) |
335 | { | 349 | { |
336 | struct slot *slot = hotplug_slot->private; | 350 | struct slot *slot = hotplug_slot->private; |
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 6c14d9e46b2e..d77138ecb098 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c | |||
@@ -1288,7 +1288,7 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) | |||
1288 | if (ACPI_SUCCESS(status)) { | 1288 | if (ACPI_SUCCESS(status)) { |
1289 | dbg("Gained control for hotplug HW for pci %s (%s)\n", | 1289 | dbg("Gained control for hotplug HW for pci %s (%s)\n", |
1290 | pci_name(dev), (char *)string.pointer); | 1290 | pci_name(dev), (char *)string.pointer); |
1291 | acpi_os_free(string.pointer); | 1291 | kfree(string.pointer); |
1292 | return 0; | 1292 | return 0; |
1293 | } | 1293 | } |
1294 | if (acpi_root_bridge(handle)) | 1294 | if (acpi_root_bridge(handle)) |
@@ -1302,7 +1302,7 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) | |||
1302 | err("Cannot get control of hotplug hardware for pci %s\n", | 1302 | err("Cannot get control of hotplug hardware for pci %s\n", |
1303 | pci_name(dev)); | 1303 | pci_name(dev)); |
1304 | 1304 | ||
1305 | acpi_os_free(string.pointer); | 1305 | kfree(string.pointer); |
1306 | return -1; | 1306 | return -1; |
1307 | } | 1307 | } |
1308 | #endif | 1308 | #endif |
@@ -1404,9 +1404,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1404 | info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, | 1404 | info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, |
1405 | pdev->subsystem_vendor, pdev->subsystem_device); | 1405 | pdev->subsystem_vendor, pdev->subsystem_device); |
1406 | 1406 | ||
1407 | if (pci_enable_device(pdev)) | ||
1408 | goto abort_free_ctlr; | ||
1409 | |||
1410 | mutex_init(&ctrl->crit_sect); | 1407 | mutex_init(&ctrl->crit_sect); |
1411 | /* setup wait queue */ | 1408 | /* setup wait queue */ |
1412 | init_waitqueue_head(&ctrl->queue); | 1409 | init_waitqueue_head(&ctrl->queue); |
@@ -1474,7 +1471,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1474 | rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); | 1471 | rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); |
1475 | if (rc) { | 1472 | if (rc) { |
1476 | err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); | 1473 | err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); |
1477 | goto abort_free_ctlr; | 1474 | goto abort_free_irq; |
1478 | } | 1475 | } |
1479 | 1476 | ||
1480 | intr_enable = intr_enable | PRSN_DETECT_ENABLE; | 1477 | intr_enable = intr_enable | PRSN_DETECT_ENABLE; |
@@ -1500,19 +1497,19 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1500 | rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); | 1497 | rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); |
1501 | if (rc) { | 1498 | if (rc) { |
1502 | err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); | 1499 | err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); |
1503 | goto abort_free_ctlr; | 1500 | goto abort_free_irq; |
1504 | } | 1501 | } |
1505 | rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); | 1502 | rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); |
1506 | if (rc) { | 1503 | if (rc) { |
1507 | err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); | 1504 | err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); |
1508 | goto abort_free_ctlr; | 1505 | goto abort_disable_intr; |
1509 | } | 1506 | } |
1510 | 1507 | ||
1511 | temp_word = 0x1F; /* Clear all events */ | 1508 | temp_word = 0x1F; /* Clear all events */ |
1512 | rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); | 1509 | rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); |
1513 | if (rc) { | 1510 | if (rc) { |
1514 | err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); | 1511 | err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); |
1515 | goto abort_free_ctlr; | 1512 | goto abort_disable_intr; |
1516 | } | 1513 | } |
1517 | 1514 | ||
1518 | if (pciehp_force) { | 1515 | if (pciehp_force) { |
@@ -1521,7 +1518,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1521 | } else { | 1518 | } else { |
1522 | rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev); | 1519 | rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev); |
1523 | if (rc) | 1520 | if (rc) |
1524 | goto abort_free_ctlr; | 1521 | goto abort_disable_intr; |
1525 | } | 1522 | } |
1526 | 1523 | ||
1527 | /* Add this HPC instance into the HPC list */ | 1524 | /* Add this HPC instance into the HPC list */ |
@@ -1548,6 +1545,21 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1548 | return 0; | 1545 | return 0; |
1549 | 1546 | ||
1550 | /* We end up here for the many possible ways to fail this API. */ | 1547 | /* We end up here for the many possible ways to fail this API. */ |
1548 | abort_disable_intr: | ||
1549 | rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); | ||
1550 | if (!rc) { | ||
1551 | temp_word &= ~(intr_enable | HP_INTR_ENABLE); | ||
1552 | rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); | ||
1553 | } | ||
1554 | if (rc) | ||
1555 | err("%s : disabling interrupts failed\n", __FUNCTION__); | ||
1556 | |||
1557 | abort_free_irq: | ||
1558 | if (pciehp_poll_mode) | ||
1559 | del_timer_sync(&php_ctlr->int_poll_timer); | ||
1560 | else | ||
1561 | free_irq(php_ctlr->irq, ctrl); | ||
1562 | |||
1551 | abort_free_ctlr: | 1563 | abort_free_ctlr: |
1552 | pcie_cap_base = saved_cap_base; | 1564 | pcie_cap_base = saved_cap_base; |
1553 | kfree(php_ctlr); | 1565 | kfree(php_ctlr); |
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index 4017fb03a0b8..854aaea09e4d 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c | |||
@@ -34,6 +34,144 @@ | |||
34 | #include "../pci.h" | 34 | #include "../pci.h" |
35 | #include "pciehp.h" | 35 | #include "pciehp.h" |
36 | 36 | ||
37 | static void program_hpp_type0(struct pci_dev *dev, struct hpp_type0 *hpp) | ||
38 | { | ||
39 | u16 pci_cmd, pci_bctl; | ||
40 | |||
41 | if (hpp->revision > 1) { | ||
42 | printk(KERN_WARNING "%s: Rev.%d type0 record not supported\n", | ||
43 | __FUNCTION__, hpp->revision); | ||
44 | return; | ||
45 | } | ||
46 | |||
47 | pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, hpp->cache_line_size); | ||
48 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, hpp->latency_timer); | ||
49 | pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); | ||
50 | if (hpp->enable_serr) | ||
51 | pci_cmd |= PCI_COMMAND_SERR; | ||
52 | else | ||
53 | pci_cmd &= ~PCI_COMMAND_SERR; | ||
54 | if (hpp->enable_perr) | ||
55 | pci_cmd |= PCI_COMMAND_PARITY; | ||
56 | else | ||
57 | pci_cmd &= ~PCI_COMMAND_PARITY; | ||
58 | pci_write_config_word(dev, PCI_COMMAND, pci_cmd); | ||
59 | |||
60 | /* Program bridge control value */ | ||
61 | if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { | ||
62 | pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, | ||
63 | hpp->latency_timer); | ||
64 | pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); | ||
65 | if (hpp->enable_serr) | ||
66 | pci_bctl |= PCI_BRIDGE_CTL_SERR; | ||
67 | else | ||
68 | pci_bctl &= ~PCI_BRIDGE_CTL_SERR; | ||
69 | if (hpp->enable_perr) | ||
70 | pci_bctl |= PCI_BRIDGE_CTL_PARITY; | ||
71 | else | ||
72 | pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; | ||
73 | pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl); | ||
74 | } | ||
75 | } | ||
76 | |||
77 | static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp) | ||
78 | { | ||
79 | int pos; | ||
80 | u16 reg16; | ||
81 | u32 reg32; | ||
82 | |||
83 | if (hpp->revision > 1) { | ||
84 | printk(KERN_WARNING "%s: Rev.%d type2 record not supported\n", | ||
85 | __FUNCTION__, hpp->revision); | ||
86 | return; | ||
87 | } | ||
88 | |||
89 | /* Find PCI Express capability */ | ||
90 | pos = pci_find_capability(dev, PCI_CAP_ID_EXP); | ||
91 | if (!pos) | ||
92 | return; | ||
93 | |||
94 | /* Initialize Device Control Register */ | ||
95 | pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, ®16); | ||
96 | reg16 = (reg16 & hpp->pci_exp_devctl_and) | hpp->pci_exp_devctl_or; | ||
97 | pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, reg16); | ||
98 | |||
99 | /* Initialize Link Control Register */ | ||
100 | if (dev->subordinate) { | ||
101 | pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, ®16); | ||
102 | reg16 = (reg16 & hpp->pci_exp_lnkctl_and) | ||
103 | | hpp->pci_exp_lnkctl_or; | ||
104 | pci_write_config_word(dev, pos + PCI_EXP_LNKCTL, reg16); | ||
105 | } | ||
106 | |||
107 | /* Find Advanced Error Reporting Enhanced Capability */ | ||
108 | pos = 256; | ||
109 | do { | ||
110 | pci_read_config_dword(dev, pos, ®32); | ||
111 | if (PCI_EXT_CAP_ID(reg32) == PCI_EXT_CAP_ID_ERR) | ||
112 | break; | ||
113 | } while ((pos = PCI_EXT_CAP_NEXT(reg32))); | ||
114 | if (!pos) | ||
115 | return; | ||
116 | |||
117 | /* Initialize Uncorrectable Error Mask Register */ | ||
118 | pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, ®32); | ||
119 | reg32 = (reg32 & hpp->unc_err_mask_and) | hpp->unc_err_mask_or; | ||
120 | pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, reg32); | ||
121 | |||
122 | /* Initialize Uncorrectable Error Severity Register */ | ||
123 | pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, ®32); | ||
124 | reg32 = (reg32 & hpp->unc_err_sever_and) | hpp->unc_err_sever_or; | ||
125 | pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, reg32); | ||
126 | |||
127 | /* Initialize Correctable Error Mask Register */ | ||
128 | pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, ®32); | ||
129 | reg32 = (reg32 & hpp->cor_err_mask_and) | hpp->cor_err_mask_or; | ||
130 | pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg32); | ||
131 | |||
132 | /* Initialize Advanced Error Capabilities and Control Register */ | ||
133 | pci_read_config_dword(dev, pos + PCI_ERR_CAP, ®32); | ||
134 | reg32 = (reg32 & hpp->adv_err_cap_and) | hpp->adv_err_cap_or; | ||
135 | pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32); | ||
136 | |||
137 | /* | ||
138 | * FIXME: The following two registers are not supported yet. | ||
139 | * | ||
140 | * o Secondary Uncorrectable Error Severity Register | ||
141 | * o Secondary Uncorrectable Error Mask Register | ||
142 | */ | ||
143 | } | ||
144 | |||
145 | static void program_fw_provided_values(struct pci_dev *dev) | ||
146 | { | ||
147 | struct pci_dev *cdev; | ||
148 | struct hotplug_params hpp; | ||
149 | |||
150 | /* Program hpp values for this device */ | ||
151 | if (!(dev->hdr_type == PCI_HEADER_TYPE_NORMAL || | ||
152 | (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && | ||
153 | (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) | ||
154 | return; | ||
155 | |||
156 | if (pciehp_get_hp_params_from_firmware(dev, &hpp)) { | ||
157 | printk(KERN_WARNING "%s: Could not get hotplug parameters\n", | ||
158 | __FUNCTION__); | ||
159 | return; | ||
160 | } | ||
161 | |||
162 | if (hpp.t2) | ||
163 | program_hpp_type2(dev, hpp.t2); | ||
164 | if (hpp.t0) | ||
165 | program_hpp_type0(dev, hpp.t0); | ||
166 | |||
167 | /* Program child devices */ | ||
168 | if (dev->subordinate) { | ||
169 | list_for_each_entry(cdev, &dev->subordinate->devices, | ||
170 | bus_list) | ||
171 | program_fw_provided_values(cdev); | ||
172 | } | ||
173 | } | ||
174 | |||
37 | static int pciehp_add_bridge(struct pci_dev *dev) | 175 | static int pciehp_add_bridge(struct pci_dev *dev) |
38 | { | 176 | { |
39 | struct pci_bus *parent = dev->bus; | 177 | struct pci_bus *parent = dev->bus; |
@@ -66,10 +204,11 @@ int pciehp_configure_device(struct slot *p_slot) | |||
66 | struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; | 204 | struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; |
67 | int num, fn; | 205 | int num, fn; |
68 | 206 | ||
69 | dev = pci_find_slot(p_slot->bus, PCI_DEVFN(p_slot->device, 0)); | 207 | dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0)); |
70 | if (dev) { | 208 | if (dev) { |
71 | err("Device %s already exists at %x:%x, cannot hot-add\n", | 209 | err("Device %s already exists at %x:%x, cannot hot-add\n", |
72 | pci_name(dev), p_slot->bus, p_slot->device); | 210 | pci_name(dev), p_slot->bus, p_slot->device); |
211 | pci_dev_put(dev); | ||
73 | return -EINVAL; | 212 | return -EINVAL; |
74 | } | 213 | } |
75 | 214 | ||
@@ -86,14 +225,15 @@ int pciehp_configure_device(struct slot *p_slot) | |||
86 | if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { | 225 | if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { |
87 | err("Cannot hot-add display device %s\n", | 226 | err("Cannot hot-add display device %s\n", |
88 | pci_name(dev)); | 227 | pci_name(dev)); |
228 | pci_dev_put(dev); | ||
89 | continue; | 229 | continue; |
90 | } | 230 | } |
91 | if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || | 231 | if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || |
92 | (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) { | 232 | (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) { |
93 | pciehp_add_bridge(dev); | 233 | pciehp_add_bridge(dev); |
94 | } | 234 | } |
95 | /* TBD: program firmware provided _HPP values */ | 235 | program_fw_provided_values(dev); |
96 | /* program_fw_provided_values(dev); */ | 236 | pci_dev_put(dev); |
97 | } | 237 | } |
98 | 238 | ||
99 | pci_bus_assign_resources(parent); | 239 | pci_bus_assign_resources(parent); |
@@ -106,18 +246,20 @@ int pciehp_unconfigure_device(struct slot *p_slot) | |||
106 | int rc = 0; | 246 | int rc = 0; |
107 | int j; | 247 | int j; |
108 | u8 bctl = 0; | 248 | u8 bctl = 0; |
249 | struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; | ||
109 | 250 | ||
110 | dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus, | 251 | dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus, |
111 | p_slot->device); | 252 | p_slot->device); |
112 | 253 | ||
113 | for (j=0; j<8 ; j++) { | 254 | for (j=0; j<8 ; j++) { |
114 | struct pci_dev* temp = pci_find_slot(p_slot->bus, | 255 | struct pci_dev* temp = pci_get_slot(parent, |
115 | (p_slot->device << 3) | j); | 256 | (p_slot->device << 3) | j); |
116 | if (!temp) | 257 | if (!temp) |
117 | continue; | 258 | continue; |
118 | if ((temp->class >> 16) == PCI_BASE_CLASS_DISPLAY) { | 259 | if ((temp->class >> 16) == PCI_BASE_CLASS_DISPLAY) { |
119 | err("Cannot remove display device %s\n", | 260 | err("Cannot remove display device %s\n", |
120 | pci_name(temp)); | 261 | pci_name(temp)); |
262 | pci_dev_put(temp); | ||
121 | continue; | 263 | continue; |
122 | } | 264 | } |
123 | if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) { | 265 | if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) { |
@@ -125,10 +267,12 @@ int pciehp_unconfigure_device(struct slot *p_slot) | |||
125 | if (bctl & PCI_BRIDGE_CTL_VGA) { | 267 | if (bctl & PCI_BRIDGE_CTL_VGA) { |
126 | err("Cannot remove display device %s\n", | 268 | err("Cannot remove display device %s\n", |
127 | pci_name(temp)); | 269 | pci_name(temp)); |
270 | pci_dev_put(temp); | ||
128 | continue; | 271 | continue; |
129 | } | 272 | } |
130 | } | 273 | } |
131 | pci_remove_bus_device(temp); | 274 | pci_remove_bus_device(temp); |
275 | pci_dev_put(temp); | ||
132 | } | 276 | } |
133 | /* | 277 | /* |
134 | * Some PCI Express root ports require fixup after hot-plug operation. | 278 | * Some PCI Express root ports require fixup after hot-plug operation. |
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index 8cb9abde736b..f31d83c2c633 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c | |||
@@ -18,11 +18,13 @@ | |||
18 | #include <linux/mutex.h> | 18 | #include <linux/mutex.h> |
19 | 19 | ||
20 | #include <asm/sn/addrs.h> | 20 | #include <asm/sn/addrs.h> |
21 | #include <asm/sn/geo.h> | ||
21 | #include <asm/sn/l1.h> | 22 | #include <asm/sn/l1.h> |
22 | #include <asm/sn/module.h> | 23 | #include <asm/sn/module.h> |
23 | #include <asm/sn/pcibr_provider.h> | 24 | #include <asm/sn/pcibr_provider.h> |
24 | #include <asm/sn/pcibus_provider_defs.h> | 25 | #include <asm/sn/pcibus_provider_defs.h> |
25 | #include <asm/sn/pcidev.h> | 26 | #include <asm/sn/pcidev.h> |
27 | #include <asm/sn/sn_feature_sets.h> | ||
26 | #include <asm/sn/sn_sal.h> | 28 | #include <asm/sn/sn_sal.h> |
27 | #include <asm/sn/types.h> | 29 | #include <asm/sn/types.h> |
28 | 30 | ||
@@ -102,8 +104,7 @@ static struct hotplug_slot_attribute sn_slot_path_attr = __ATTR_RO(path); | |||
102 | static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device) | 104 | static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device) |
103 | { | 105 | { |
104 | struct pcibus_info *pcibus_info; | 106 | struct pcibus_info *pcibus_info; |
105 | int bricktype; | 107 | u16 busnum, segment, ioboard_type; |
106 | int bus_num; | ||
107 | 108 | ||
108 | pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus); | 109 | pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus); |
109 | 110 | ||
@@ -111,12 +112,14 @@ static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device) | |||
111 | if (!(pcibus_info->pbi_valid_devices & (1 << device))) | 112 | if (!(pcibus_info->pbi_valid_devices & (1 << device))) |
112 | return -EPERM; | 113 | return -EPERM; |
113 | 114 | ||
114 | bricktype = MODULE_GET_BTYPE(pcibus_info->pbi_moduleid); | 115 | ioboard_type = sn_ioboard_to_pci_bus(pci_bus); |
115 | bus_num = pcibus_info->pbi_buscommon.bs_persist_busnum & 0xf; | 116 | busnum = pcibus_info->pbi_buscommon.bs_persist_busnum; |
117 | segment = pci_domain_nr(pci_bus) & 0xf; | ||
116 | 118 | ||
117 | /* Do not allow hotplug operations on base I/O cards */ | 119 | /* Do not allow hotplug operations on base I/O cards */ |
118 | if ((bricktype == L1_BRICKTYPE_IX || bricktype == L1_BRICKTYPE_IA) && | 120 | if ((ioboard_type == L1_BRICKTYPE_IX || |
119 | (bus_num == 1 && device != 1)) | 121 | ioboard_type == L1_BRICKTYPE_IA) && |
122 | (segment == 1 && busnum == 0 && device != 1)) | ||
120 | return -EPERM; | 123 | return -EPERM; |
121 | 124 | ||
122 | return 1; | 125 | return 1; |
@@ -125,23 +128,23 @@ static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device) | |||
125 | static int sn_pci_bus_valid(struct pci_bus *pci_bus) | 128 | static int sn_pci_bus_valid(struct pci_bus *pci_bus) |
126 | { | 129 | { |
127 | struct pcibus_info *pcibus_info; | 130 | struct pcibus_info *pcibus_info; |
128 | int asic_type; | 131 | u32 asic_type; |
129 | int bricktype; | 132 | u16 ioboard_type; |
130 | |||
131 | pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus); | ||
132 | 133 | ||
133 | /* Don't register slots hanging off the TIOCA bus */ | 134 | /* Don't register slots hanging off the TIOCA bus */ |
135 | pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus); | ||
134 | asic_type = pcibus_info->pbi_buscommon.bs_asic_type; | 136 | asic_type = pcibus_info->pbi_buscommon.bs_asic_type; |
135 | if (asic_type == PCIIO_ASIC_TYPE_TIOCA) | 137 | if (asic_type == PCIIO_ASIC_TYPE_TIOCA) |
136 | return -EPERM; | 138 | return -EPERM; |
137 | 139 | ||
138 | /* Only register slots in I/O Bricks that support hotplug */ | 140 | /* Only register slots in I/O Bricks that support hotplug */ |
139 | bricktype = MODULE_GET_BTYPE(pcibus_info->pbi_moduleid); | 141 | ioboard_type = sn_ioboard_to_pci_bus(pci_bus); |
140 | switch (bricktype) { | 142 | switch (ioboard_type) { |
141 | case L1_BRICKTYPE_IX: | 143 | case L1_BRICKTYPE_IX: |
142 | case L1_BRICKTYPE_PX: | 144 | case L1_BRICKTYPE_PX: |
143 | case L1_BRICKTYPE_IA: | 145 | case L1_BRICKTYPE_IA: |
144 | case L1_BRICKTYPE_PA: | 146 | case L1_BRICKTYPE_PA: |
147 | case L1_BOARDTYPE_PCIX3SLOT: | ||
145 | return 1; | 148 | return 1; |
146 | break; | 149 | break; |
147 | default: | 150 | default: |
@@ -175,14 +178,11 @@ static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot, | |||
175 | slot->pci_bus = pci_bus; | 178 | slot->pci_bus = pci_bus; |
176 | sprintf(bss_hotplug_slot->name, "%04x:%02x:%02x", | 179 | sprintf(bss_hotplug_slot->name, "%04x:%02x:%02x", |
177 | pci_domain_nr(pci_bus), | 180 | pci_domain_nr(pci_bus), |
178 | ((int)pcibus_info->pbi_buscommon.bs_persist_busnum) & 0xf, | 181 | ((u16)pcibus_info->pbi_buscommon.bs_persist_busnum), |
179 | device + 1); | 182 | device + 1); |
180 | sprintf(slot->physical_path, "module_%c%c%c%c%.2d", | 183 | |
181 | '0'+RACK_GET_CLASS(MODULE_GET_RACK(pcibus_info->pbi_moduleid)), | 184 | sn_generate_path(pci_bus, slot->physical_path); |
182 | '0'+RACK_GET_GROUP(MODULE_GET_RACK(pcibus_info->pbi_moduleid)), | 185 | |
183 | '0'+RACK_GET_NUM(MODULE_GET_RACK(pcibus_info->pbi_moduleid)), | ||
184 | MODULE_GET_BTCHAR(pcibus_info->pbi_moduleid), | ||
185 | MODULE_GET_BPOS(pcibus_info->pbi_moduleid)); | ||
186 | slot->hotplug_slot = bss_hotplug_slot; | 186 | slot->hotplug_slot = bss_hotplug_slot; |
187 | list_add(&slot->hp_list, &sn_hp_list); | 187 | list_add(&slot->hp_list, &sn_hp_list); |
188 | 188 | ||
@@ -461,10 +461,12 @@ static inline int get_power_status(struct hotplug_slot *bss_hotplug_slot, | |||
461 | { | 461 | { |
462 | struct slot *slot = bss_hotplug_slot->private; | 462 | struct slot *slot = bss_hotplug_slot->private; |
463 | struct pcibus_info *pcibus_info; | 463 | struct pcibus_info *pcibus_info; |
464 | u32 power; | ||
464 | 465 | ||
465 | pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); | 466 | pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); |
466 | mutex_lock(&sn_hotplug_mutex); | 467 | mutex_lock(&sn_hotplug_mutex); |
467 | *value = pcibus_info->pbi_enabled_devices & (1 << slot->device_num); | 468 | power = pcibus_info->pbi_enabled_devices & (1 << slot->device_num); |
469 | *value = power ? 1 : 0; | ||
468 | mutex_unlock(&sn_hotplug_mutex); | 470 | mutex_unlock(&sn_hotplug_mutex); |
469 | return 0; | 471 | return 0; |
470 | } | 472 | } |
@@ -553,8 +555,8 @@ static int sn_pci_hotplug_init(void) | |||
553 | int rc; | 555 | int rc; |
554 | int registered = 0; | 556 | int registered = 0; |
555 | 557 | ||
556 | if (sn_sal_rev() < SGI_HOTPLUG_PROM_REV) { | 558 | if (!sn_prom_feature_available(PRF_HOTPLUG_SUPPORT)) { |
557 | printk(KERN_ERR "%s: PROM version must be greater than 4.30\n", | 559 | printk(KERN_ERR "%s: PROM version does not support hotplug.\n", |
558 | __FUNCTION__); | 560 | __FUNCTION__); |
559 | return -EPERM; | 561 | return -EPERM; |
560 | } | 562 | } |
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index 5c70f43908c4..7208b95c6ee7 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h | |||
@@ -168,9 +168,9 @@ struct controller { | |||
168 | * error Messages | 168 | * error Messages |
169 | */ | 169 | */ |
170 | #define msg_initialization_err "Initialization failure, error=%d\n" | 170 | #define msg_initialization_err "Initialization failure, error=%d\n" |
171 | #define msg_button_on "PCI slot #%d - powering on due to button press.\n" | 171 | #define msg_button_on "PCI slot #%s - powering on due to button press.\n" |
172 | #define msg_button_off "PCI slot #%d - powering off due to button press.\n" | 172 | #define msg_button_off "PCI slot #%s - powering off due to button press.\n" |
173 | #define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n" | 173 | #define msg_button_cancel "PCI slot #%s - action canceled due to button press.\n" |
174 | 174 | ||
175 | /* sysfs functions for the hotplug controller info */ | 175 | /* sysfs functions for the hotplug controller info */ |
176 | extern void shpchp_create_ctrl_files (struct controller *ctrl); | 176 | extern void shpchp_create_ctrl_files (struct controller *ctrl); |
@@ -196,7 +196,7 @@ extern void queue_pushbutton_work(void *data); | |||
196 | static inline int get_hp_params_from_firmware(struct pci_dev *dev, | 196 | static inline int get_hp_params_from_firmware(struct pci_dev *dev, |
197 | struct hotplug_params *hpp) | 197 | struct hotplug_params *hpp) |
198 | { | 198 | { |
199 | if (ACPI_FAILURE(acpi_get_hp_params_from_firmware(dev, hpp))) | 199 | if (ACPI_FAILURE(acpi_get_hp_params_from_firmware(dev->bus, hpp))) |
200 | return -ENODEV; | 200 | return -ENODEV; |
201 | return 0; | 201 | return 0; |
202 | } | 202 | } |
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 3be4d492ccc2..a14e7de19846 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c | |||
@@ -491,16 +491,9 @@ static int __init shpcd_init(void) | |||
491 | shpchp_poll_mode = 1; | 491 | shpchp_poll_mode = 1; |
492 | #endif | 492 | #endif |
493 | 493 | ||
494 | shpchp_wq = create_singlethread_workqueue("shpchpd"); | ||
495 | if (!shpchp_wq) | ||
496 | return -ENOMEM; | ||
497 | |||
498 | retval = pci_register_driver(&shpc_driver); | 494 | retval = pci_register_driver(&shpc_driver); |
499 | dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval); | 495 | dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval); |
500 | info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); | 496 | info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); |
501 | if (retval) { | ||
502 | destroy_workqueue(shpchp_wq); | ||
503 | } | ||
504 | return retval; | 497 | return retval; |
505 | } | 498 | } |
506 | 499 | ||
@@ -508,7 +501,6 @@ static void __exit shpcd_cleanup(void) | |||
508 | { | 501 | { |
509 | dbg("unload_shpchpd()\n"); | 502 | dbg("unload_shpchpd()\n"); |
510 | pci_unregister_driver(&shpc_driver); | 503 | pci_unregister_driver(&shpc_driver); |
511 | destroy_workqueue(shpchp_wq); | ||
512 | info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); | 504 | info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); |
513 | } | 505 | } |
514 | 506 | ||
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 4e6381481c55..c39901dbff20 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c | |||
@@ -72,7 +72,7 @@ u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id) | |||
72 | /* | 72 | /* |
73 | * Button pressed - See if need to TAKE ACTION!!! | 73 | * Button pressed - See if need to TAKE ACTION!!! |
74 | */ | 74 | */ |
75 | info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot); | 75 | info("Button pressed on Slot(%s)\n", p_slot->name); |
76 | event_type = INT_BUTTON_PRESS; | 76 | event_type = INT_BUTTON_PRESS; |
77 | 77 | ||
78 | queue_interrupt_event(p_slot, event_type); | 78 | queue_interrupt_event(p_slot, event_type); |
@@ -101,7 +101,7 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id) | |||
101 | /* | 101 | /* |
102 | * Switch opened | 102 | * Switch opened |
103 | */ | 103 | */ |
104 | info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot); | 104 | info("Latch open on Slot(%s)\n", p_slot->name); |
105 | event_type = INT_SWITCH_OPEN; | 105 | event_type = INT_SWITCH_OPEN; |
106 | if (p_slot->pwr_save && p_slot->presence_save) { | 106 | if (p_slot->pwr_save && p_slot->presence_save) { |
107 | event_type = INT_POWER_FAULT; | 107 | event_type = INT_POWER_FAULT; |
@@ -111,7 +111,7 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id) | |||
111 | /* | 111 | /* |
112 | * Switch closed | 112 | * Switch closed |
113 | */ | 113 | */ |
114 | info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot); | 114 | info("Latch close on Slot(%s)\n", p_slot->name); |
115 | event_type = INT_SWITCH_CLOSE; | 115 | event_type = INT_SWITCH_CLOSE; |
116 | } | 116 | } |
117 | 117 | ||
@@ -139,13 +139,13 @@ u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id) | |||
139 | /* | 139 | /* |
140 | * Card Present | 140 | * Card Present |
141 | */ | 141 | */ |
142 | info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot); | 142 | info("Card present on Slot(%s)\n", p_slot->name); |
143 | event_type = INT_PRESENCE_ON; | 143 | event_type = INT_PRESENCE_ON; |
144 | } else { | 144 | } else { |
145 | /* | 145 | /* |
146 | * Not Present | 146 | * Not Present |
147 | */ | 147 | */ |
148 | info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot); | 148 | info("Card not present on Slot(%s)\n", p_slot->name); |
149 | event_type = INT_PRESENCE_OFF; | 149 | event_type = INT_PRESENCE_OFF; |
150 | } | 150 | } |
151 | 151 | ||
@@ -169,14 +169,14 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) | |||
169 | /* | 169 | /* |
170 | * Power fault Cleared | 170 | * Power fault Cleared |
171 | */ | 171 | */ |
172 | info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot); | 172 | info("Power fault cleared on Slot(%s)\n", p_slot->name); |
173 | p_slot->status = 0x00; | 173 | p_slot->status = 0x00; |
174 | event_type = INT_POWER_FAULT_CLEAR; | 174 | event_type = INT_POWER_FAULT_CLEAR; |
175 | } else { | 175 | } else { |
176 | /* | 176 | /* |
177 | * Power fault | 177 | * Power fault |
178 | */ | 178 | */ |
179 | info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot); | 179 | info("Power fault on Slot(%s)\n", p_slot->name); |
180 | event_type = INT_POWER_FAULT; | 180 | event_type = INT_POWER_FAULT; |
181 | /* set power fault status for this board */ | 181 | /* set power fault status for this board */ |
182 | p_slot->status = 0xFF; | 182 | p_slot->status = 0xFF; |
@@ -496,10 +496,10 @@ static void handle_button_press_event(struct slot *p_slot) | |||
496 | p_slot->hpc_ops->get_power_status(p_slot, &getstatus); | 496 | p_slot->hpc_ops->get_power_status(p_slot, &getstatus); |
497 | if (getstatus) { | 497 | if (getstatus) { |
498 | p_slot->state = BLINKINGOFF_STATE; | 498 | p_slot->state = BLINKINGOFF_STATE; |
499 | info(msg_button_off, p_slot->number); | 499 | info(msg_button_off, p_slot->name); |
500 | } else { | 500 | } else { |
501 | p_slot->state = BLINKINGON_STATE; | 501 | p_slot->state = BLINKINGON_STATE; |
502 | info(msg_button_on, p_slot->number); | 502 | info(msg_button_on, p_slot->name); |
503 | } | 503 | } |
504 | /* blink green LED and turn off amber */ | 504 | /* blink green LED and turn off amber */ |
505 | p_slot->hpc_ops->green_led_blink(p_slot); | 505 | p_slot->hpc_ops->green_led_blink(p_slot); |
@@ -522,7 +522,7 @@ static void handle_button_press_event(struct slot *p_slot) | |||
522 | else | 522 | else |
523 | p_slot->hpc_ops->green_led_off(p_slot); | 523 | p_slot->hpc_ops->green_led_off(p_slot); |
524 | p_slot->hpc_ops->set_attention_status(p_slot, 0); | 524 | p_slot->hpc_ops->set_attention_status(p_slot, 0); |
525 | info(msg_button_cancel, p_slot->number); | 525 | info(msg_button_cancel, p_slot->name); |
526 | p_slot->state = STATIC_STATE; | 526 | p_slot->state = STATIC_STATE; |
527 | break; | 527 | break; |
528 | case POWEROFF_STATE: | 528 | case POWEROFF_STATE: |
@@ -575,17 +575,17 @@ static int shpchp_enable_slot (struct slot *p_slot) | |||
575 | mutex_lock(&p_slot->ctrl->crit_sect); | 575 | mutex_lock(&p_slot->ctrl->crit_sect); |
576 | rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); | 576 | rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); |
577 | if (rc || !getstatus) { | 577 | if (rc || !getstatus) { |
578 | info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); | 578 | info("No adapter on slot(%s)\n", p_slot->name); |
579 | goto out; | 579 | goto out; |
580 | } | 580 | } |
581 | rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 581 | rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
582 | if (rc || getstatus) { | 582 | if (rc || getstatus) { |
583 | info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); | 583 | info("Latch open on slot(%s)\n", p_slot->name); |
584 | goto out; | 584 | goto out; |
585 | } | 585 | } |
586 | rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); | 586 | rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); |
587 | if (rc || getstatus) { | 587 | if (rc || getstatus) { |
588 | info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number); | 588 | info("Already enabled on slot(%s)\n", p_slot->name); |
589 | goto out; | 589 | goto out; |
590 | } | 590 | } |
591 | 591 | ||
@@ -634,17 +634,17 @@ static int shpchp_disable_slot (struct slot *p_slot) | |||
634 | 634 | ||
635 | rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); | 635 | rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); |
636 | if (rc || !getstatus) { | 636 | if (rc || !getstatus) { |
637 | info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); | 637 | info("No adapter on slot(%s)\n", p_slot->name); |
638 | goto out; | 638 | goto out; |
639 | } | 639 | } |
640 | rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 640 | rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
641 | if (rc || getstatus) { | 641 | if (rc || getstatus) { |
642 | info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); | 642 | info("Latch open on slot(%s)\n", p_slot->name); |
643 | goto out; | 643 | goto out; |
644 | } | 644 | } |
645 | rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); | 645 | rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); |
646 | if (rc || !getstatus) { | 646 | if (rc || !getstatus) { |
647 | info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); | 647 | info("Already disabled slot(%s)\n", p_slot->name); |
648 | goto out; | 648 | goto out; |
649 | } | 649 | } |
650 | 650 | ||
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 66123cf4deaa..45facaad39bd 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c | |||
@@ -90,77 +90,94 @@ | |||
90 | #define MRLSENSOR 0x40000000 | 90 | #define MRLSENSOR 0x40000000 |
91 | #define ATTN_BUTTON 0x80000000 | 91 | #define ATTN_BUTTON 0x80000000 |
92 | 92 | ||
93 | /* Slot Status Field Definitions */ | 93 | /* |
94 | /* Slot State */ | 94 | * Interrupt Locator Register definitions |
95 | #define PWR_ONLY 0x0001 | 95 | */ |
96 | #define ENABLED 0x0002 | 96 | #define CMD_INTR_PENDING (1 << 0) |
97 | #define DISABLED 0x0003 | 97 | #define SLOT_INTR_PENDING(i) (1 << (i + 1)) |
98 | |||
99 | /* Power Indicator State */ | ||
100 | #define PWR_LED_ON 0x0004 | ||
101 | #define PWR_LED_BLINK 0x0008 | ||
102 | #define PWR_LED_OFF 0x000c | ||
103 | |||
104 | /* Attention Indicator State */ | ||
105 | #define ATTEN_LED_ON 0x0010 | ||
106 | #define ATTEN_LED_BLINK 0x0020 | ||
107 | #define ATTEN_LED_OFF 0x0030 | ||
108 | |||
109 | /* Power Fault */ | ||
110 | #define pwr_fault 0x0040 | ||
111 | |||
112 | /* Attention Button */ | ||
113 | #define ATTEN_BUTTON 0x0080 | ||
114 | |||
115 | /* MRL Sensor */ | ||
116 | #define MRL_SENSOR 0x0100 | ||
117 | |||
118 | /* 66 MHz Capable */ | ||
119 | #define IS_66MHZ_CAP 0x0200 | ||
120 | |||
121 | /* PRSNT1#/PRSNT2# */ | ||
122 | #define SLOT_EMP 0x0c00 | ||
123 | |||
124 | /* PCI-X Capability */ | ||
125 | #define NON_PCIX 0x0000 | ||
126 | #define PCIX_66 0x1000 | ||
127 | #define PCIX_133 0x3000 | ||
128 | #define PCIX_266 0x4000 /* For PI = 2 only */ | ||
129 | #define PCIX_533 0x5000 /* For PI = 2 only */ | ||
130 | |||
131 | /* SHPC 'write' operations/commands */ | ||
132 | |||
133 | /* Slot operation - 0x00h to 0x3Fh */ | ||
134 | |||
135 | #define NO_CHANGE 0x00 | ||
136 | |||
137 | /* Slot state - Bits 0 & 1 of controller command register */ | ||
138 | #define SET_SLOT_PWR 0x01 | ||
139 | #define SET_SLOT_ENABLE 0x02 | ||
140 | #define SET_SLOT_DISABLE 0x03 | ||
141 | 98 | ||
142 | /* Power indicator state - Bits 2 & 3 of controller command register*/ | 99 | /* |
143 | #define SET_PWR_ON 0x04 | 100 | * Controller SERR-INT Register |
144 | #define SET_PWR_BLINK 0x08 | 101 | */ |
145 | #define SET_PWR_OFF 0x0C | 102 | #define GLOBAL_INTR_MASK (1 << 0) |
103 | #define GLOBAL_SERR_MASK (1 << 1) | ||
104 | #define COMMAND_INTR_MASK (1 << 2) | ||
105 | #define ARBITER_SERR_MASK (1 << 3) | ||
106 | #define COMMAND_DETECTED (1 << 16) | ||
107 | #define ARBITER_DETECTED (1 << 17) | ||
108 | #define SERR_INTR_RSVDZ_MASK 0xfffc0000 | ||
146 | 109 | ||
147 | /* Attention indicator state - Bits 4 & 5 of controller command register*/ | 110 | /* |
148 | #define SET_ATTN_ON 0x010 | 111 | * Logical Slot Register definitions |
149 | #define SET_ATTN_BLINK 0x020 | 112 | */ |
150 | #define SET_ATTN_OFF 0x030 | 113 | #define SLOT_REG(i) (SLOT1 + (4 * i)) |
114 | |||
115 | #define SLOT_STATE_SHIFT (0) | ||
116 | #define SLOT_STATE_MASK (3 << 0) | ||
117 | #define SLOT_STATE_PWRONLY (1) | ||
118 | #define SLOT_STATE_ENABLED (2) | ||
119 | #define SLOT_STATE_DISABLED (3) | ||
120 | #define PWR_LED_STATE_SHIFT (2) | ||
121 | #define PWR_LED_STATE_MASK (3 << 2) | ||
122 | #define ATN_LED_STATE_SHIFT (4) | ||
123 | #define ATN_LED_STATE_MASK (3 << 4) | ||
124 | #define ATN_LED_STATE_ON (1) | ||
125 | #define ATN_LED_STATE_BLINK (2) | ||
126 | #define ATN_LED_STATE_OFF (3) | ||
127 | #define POWER_FAULT (1 << 6) | ||
128 | #define ATN_BUTTON (1 << 7) | ||
129 | #define MRL_SENSOR (1 << 8) | ||
130 | #define MHZ66_CAP (1 << 9) | ||
131 | #define PRSNT_SHIFT (10) | ||
132 | #define PRSNT_MASK (3 << 10) | ||
133 | #define PCIX_CAP_SHIFT (12) | ||
134 | #define PCIX_CAP_MASK_PI1 (3 << 12) | ||
135 | #define PCIX_CAP_MASK_PI2 (7 << 12) | ||
136 | #define PRSNT_CHANGE_DETECTED (1 << 16) | ||
137 | #define ISO_PFAULT_DETECTED (1 << 17) | ||
138 | #define BUTTON_PRESS_DETECTED (1 << 18) | ||
139 | #define MRL_CHANGE_DETECTED (1 << 19) | ||
140 | #define CON_PFAULT_DETECTED (1 << 20) | ||
141 | #define PRSNT_CHANGE_INTR_MASK (1 << 24) | ||
142 | #define ISO_PFAULT_INTR_MASK (1 << 25) | ||
143 | #define BUTTON_PRESS_INTR_MASK (1 << 26) | ||
144 | #define MRL_CHANGE_INTR_MASK (1 << 27) | ||
145 | #define CON_PFAULT_INTR_MASK (1 << 28) | ||
146 | #define MRL_CHANGE_SERR_MASK (1 << 29) | ||
147 | #define CON_PFAULT_SERR_MASK (1 << 30) | ||
148 | #define SLOT_REG_RSVDZ_MASK (1 << 15) | (7 << 21) | ||
151 | 149 | ||
152 | /* Set bus speed/mode A - 0x40h to 0x47h */ | 150 | /* |
153 | #define SETA_PCI_33MHZ 0x40 | 151 | * SHPC Command Code definitnions |
152 | * | ||
153 | * Slot Operation 00h - 3Fh | ||
154 | * Set Bus Segment Speed/Mode A 40h - 47h | ||
155 | * Power-Only All Slots 48h | ||
156 | * Enable All Slots 49h | ||
157 | * Set Bus Segment Speed/Mode B (PI=2) 50h - 5Fh | ||
158 | * Reserved Command Codes 60h - BFh | ||
159 | * Vendor Specific Commands C0h - FFh | ||
160 | */ | ||
161 | #define SET_SLOT_PWR 0x01 /* Slot Operation */ | ||
162 | #define SET_SLOT_ENABLE 0x02 | ||
163 | #define SET_SLOT_DISABLE 0x03 | ||
164 | #define SET_PWR_ON 0x04 | ||
165 | #define SET_PWR_BLINK 0x08 | ||
166 | #define SET_PWR_OFF 0x0c | ||
167 | #define SET_ATTN_ON 0x10 | ||
168 | #define SET_ATTN_BLINK 0x20 | ||
169 | #define SET_ATTN_OFF 0x30 | ||
170 | #define SETA_PCI_33MHZ 0x40 /* Set Bus Segment Speed/Mode A */ | ||
154 | #define SETA_PCI_66MHZ 0x41 | 171 | #define SETA_PCI_66MHZ 0x41 |
155 | #define SETA_PCIX_66MHZ 0x42 | 172 | #define SETA_PCIX_66MHZ 0x42 |
156 | #define SETA_PCIX_100MHZ 0x43 | 173 | #define SETA_PCIX_100MHZ 0x43 |
157 | #define SETA_PCIX_133MHZ 0x44 | 174 | #define SETA_PCIX_133MHZ 0x44 |
158 | #define RESERV_1 0x45 | 175 | #define SETA_RESERVED1 0x45 |
159 | #define RESERV_2 0x46 | 176 | #define SETA_RESERVED2 0x46 |
160 | #define RESERV_3 0x47 | 177 | #define SETA_RESERVED3 0x47 |
161 | 178 | #define SET_PWR_ONLY_ALL 0x48 /* Power-Only All Slots */ | |
162 | /* Set bus speed/mode B - 0x50h to 0x5fh */ | 179 | #define SET_ENABLE_ALL 0x49 /* Enable All Slots */ |
163 | #define SETB_PCI_33MHZ 0x50 | 180 | #define SETB_PCI_33MHZ 0x50 /* Set Bus Segment Speed/Mode B */ |
164 | #define SETB_PCI_66MHZ 0x51 | 181 | #define SETB_PCI_66MHZ 0x51 |
165 | #define SETB_PCIX_66MHZ_PM 0x52 | 182 | #define SETB_PCIX_66MHZ_PM 0x52 |
166 | #define SETB_PCIX_100MHZ_PM 0x53 | 183 | #define SETB_PCIX_100MHZ_PM 0x53 |
@@ -174,81 +191,115 @@ | |||
174 | #define SETB_PCIX_66MHZ_533 0x5b | 191 | #define SETB_PCIX_66MHZ_533 0x5b |
175 | #define SETB_PCIX_100MHZ_533 0x5c | 192 | #define SETB_PCIX_100MHZ_533 0x5c |
176 | #define SETB_PCIX_133MHZ_533 0x5d | 193 | #define SETB_PCIX_133MHZ_533 0x5d |
194 | #define SETB_RESERVED1 0x5e | ||
195 | #define SETB_RESERVED2 0x5f | ||
177 | 196 | ||
178 | 197 | /* | |
179 | /* Power-on all slots - 0x48h */ | 198 | * SHPC controller command error code |
180 | #define SET_PWR_ON_ALL 0x48 | 199 | */ |
181 | |||
182 | /* Enable all slots - 0x49h */ | ||
183 | #define SET_ENABLE_ALL 0x49 | ||
184 | |||
185 | /* SHPC controller command error code */ | ||
186 | #define SWITCH_OPEN 0x1 | 200 | #define SWITCH_OPEN 0x1 |
187 | #define INVALID_CMD 0x2 | 201 | #define INVALID_CMD 0x2 |
188 | #define INVALID_SPEED_MODE 0x4 | 202 | #define INVALID_SPEED_MODE 0x4 |
189 | 203 | ||
190 | /* For accessing SHPC Working Register Set */ | 204 | /* |
205 | * For accessing SHPC Working Register Set via PCI Configuration Space | ||
206 | */ | ||
191 | #define DWORD_SELECT 0x2 | 207 | #define DWORD_SELECT 0x2 |
192 | #define DWORD_DATA 0x4 | 208 | #define DWORD_DATA 0x4 |
193 | #define BASE_OFFSET 0x0 | ||
194 | 209 | ||
195 | /* Field Offset in Logical Slot Register - byte boundary */ | 210 | /* Field Offset in Logical Slot Register - byte boundary */ |
196 | #define SLOT_EVENT_LATCH 0x2 | 211 | #define SLOT_EVENT_LATCH 0x2 |
197 | #define SLOT_SERR_INT_MASK 0x3 | 212 | #define SLOT_SERR_INT_MASK 0x3 |
198 | 213 | ||
199 | static spinlock_t hpc_event_lock; | ||
200 | |||
201 | DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ | 214 | DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ |
202 | static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */ | 215 | static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */ |
203 | static int ctlr_seq_num = 0; /* Controller sequenc # */ | 216 | static int ctlr_seq_num = 0; /* Controller sequenc # */ |
204 | static spinlock_t list_lock; | 217 | static spinlock_t list_lock; |
205 | 218 | ||
206 | static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs); | 219 | static atomic_t shpchp_num_controllers = ATOMIC_INIT(0); |
207 | 220 | ||
208 | static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds); | 221 | static irqreturn_t shpc_isr(int irq, void *dev_id, struct pt_regs *regs); |
222 | static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int sec); | ||
209 | static int hpc_check_cmd_status(struct controller *ctrl); | 223 | static int hpc_check_cmd_status(struct controller *ctrl); |
210 | 224 | ||
211 | /* This is the interrupt polling timeout function. */ | 225 | static inline u8 shpc_readb(struct controller *ctrl, int reg) |
212 | static void int_poll_timeout(unsigned long lphp_ctlr) | ||
213 | { | 226 | { |
214 | struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr; | 227 | return readb(ctrl->hpc_ctlr_handle->creg + reg); |
228 | } | ||
215 | 229 | ||
216 | DBG_ENTER_ROUTINE | 230 | static inline void shpc_writeb(struct controller *ctrl, int reg, u8 val) |
231 | { | ||
232 | writeb(val, ctrl->hpc_ctlr_handle->creg + reg); | ||
233 | } | ||
217 | 234 | ||
218 | if ( !php_ctlr ) { | 235 | static inline u16 shpc_readw(struct controller *ctrl, int reg) |
219 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | 236 | { |
220 | return; | 237 | return readw(ctrl->hpc_ctlr_handle->creg + reg); |
221 | } | 238 | } |
222 | 239 | ||
223 | /* Poll for interrupt events. regs == NULL => polling */ | 240 | static inline void shpc_writew(struct controller *ctrl, int reg, u16 val) |
224 | shpc_isr( 0, (void *)php_ctlr, NULL ); | 241 | { |
242 | writew(val, ctrl->hpc_ctlr_handle->creg + reg); | ||
243 | } | ||
225 | 244 | ||
226 | init_timer(&php_ctlr->int_poll_timer); | 245 | static inline u32 shpc_readl(struct controller *ctrl, int reg) |
227 | if (!shpchp_poll_time) | 246 | { |
228 | shpchp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/ | 247 | return readl(ctrl->hpc_ctlr_handle->creg + reg); |
248 | } | ||
229 | 249 | ||
230 | start_int_poll_timer(php_ctlr, shpchp_poll_time); | 250 | static inline void shpc_writel(struct controller *ctrl, int reg, u32 val) |
231 | 251 | { | |
232 | return; | 252 | writel(val, ctrl->hpc_ctlr_handle->creg + reg); |
233 | } | 253 | } |
234 | 254 | ||
235 | /* This function starts the interrupt polling timer. */ | 255 | static inline int shpc_indirect_read(struct controller *ctrl, int index, |
236 | static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds) | 256 | u32 *value) |
237 | { | 257 | { |
238 | if (!php_ctlr) { | 258 | int rc; |
239 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | 259 | u32 cap_offset = ctrl->cap_offset; |
240 | return; | 260 | struct pci_dev *pdev = ctrl->pci_dev; |
241 | } | 261 | |
262 | rc = pci_write_config_byte(pdev, cap_offset + DWORD_SELECT, index); | ||
263 | if (rc) | ||
264 | return rc; | ||
265 | return pci_read_config_dword(pdev, cap_offset + DWORD_DATA, value); | ||
266 | } | ||
267 | |||
268 | /* | ||
269 | * This is the interrupt polling timeout function. | ||
270 | */ | ||
271 | static void int_poll_timeout(unsigned long lphp_ctlr) | ||
272 | { | ||
273 | struct php_ctlr_state_s *php_ctlr = | ||
274 | (struct php_ctlr_state_s *)lphp_ctlr; | ||
275 | |||
276 | DBG_ENTER_ROUTINE | ||
277 | |||
278 | /* Poll for interrupt events. regs == NULL => polling */ | ||
279 | shpc_isr(0, php_ctlr->callback_instance_id, NULL); | ||
280 | |||
281 | init_timer(&php_ctlr->int_poll_timer); | ||
282 | if (!shpchp_poll_time) | ||
283 | shpchp_poll_time = 2; /* default polling interval is 2 sec */ | ||
242 | 284 | ||
243 | if ( ( seconds <= 0 ) || ( seconds > 60 ) ) | 285 | start_int_poll_timer(php_ctlr, shpchp_poll_time); |
244 | seconds = 2; /* Clamp to sane value */ | ||
245 | 286 | ||
246 | php_ctlr->int_poll_timer.function = &int_poll_timeout; | 287 | DBG_LEAVE_ROUTINE |
247 | php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr; /* Instance data */ | 288 | } |
248 | php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ; | ||
249 | add_timer(&php_ctlr->int_poll_timer); | ||
250 | 289 | ||
251 | return; | 290 | /* |
291 | * This function starts the interrupt polling timer. | ||
292 | */ | ||
293 | static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int sec) | ||
294 | { | ||
295 | /* Clamp to sane value */ | ||
296 | if ((sec <= 0) || (sec > 60)) | ||
297 | sec = 2; | ||
298 | |||
299 | php_ctlr->int_poll_timer.function = &int_poll_timeout; | ||
300 | php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr; | ||
301 | php_ctlr->int_poll_timer.expires = jiffies + sec * HZ; | ||
302 | add_timer(&php_ctlr->int_poll_timer); | ||
252 | } | 303 | } |
253 | 304 | ||
254 | static inline int shpc_wait_cmd(struct controller *ctrl) | 305 | static inline int shpc_wait_cmd(struct controller *ctrl) |
@@ -272,7 +323,7 @@ static inline int shpc_wait_cmd(struct controller *ctrl) | |||
272 | 323 | ||
273 | static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) | 324 | static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) |
274 | { | 325 | { |
275 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 326 | struct controller *ctrl = slot->ctrl; |
276 | u16 cmd_status; | 327 | u16 cmd_status; |
277 | int retval = 0; | 328 | int retval = 0; |
278 | u16 temp_word; | 329 | u16 temp_word; |
@@ -282,14 +333,8 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) | |||
282 | 333 | ||
283 | mutex_lock(&slot->ctrl->cmd_lock); | 334 | mutex_lock(&slot->ctrl->cmd_lock); |
284 | 335 | ||
285 | if (!php_ctlr) { | ||
286 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | ||
287 | retval = -EINVAL; | ||
288 | goto out; | ||
289 | } | ||
290 | |||
291 | for (i = 0; i < 10; i++) { | 336 | for (i = 0; i < 10; i++) { |
292 | cmd_status = readw(php_ctlr->creg + CMD_STATUS); | 337 | cmd_status = shpc_readw(ctrl, CMD_STATUS); |
293 | 338 | ||
294 | if (!(cmd_status & 0x1)) | 339 | if (!(cmd_status & 0x1)) |
295 | break; | 340 | break; |
@@ -297,7 +342,7 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) | |||
297 | msleep(100); | 342 | msleep(100); |
298 | } | 343 | } |
299 | 344 | ||
300 | cmd_status = readw(php_ctlr->creg + CMD_STATUS); | 345 | cmd_status = shpc_readw(ctrl, CMD_STATUS); |
301 | 346 | ||
302 | if (cmd_status & 0x1) { | 347 | if (cmd_status & 0x1) { |
303 | /* After 1 sec and and the controller is still busy */ | 348 | /* After 1 sec and and the controller is still busy */ |
@@ -314,7 +359,7 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) | |||
314 | * command. | 359 | * command. |
315 | */ | 360 | */ |
316 | slot->ctrl->cmd_busy = 1; | 361 | slot->ctrl->cmd_busy = 1; |
317 | writew(temp_word, php_ctlr->creg + CMD); | 362 | shpc_writew(ctrl, CMD, temp_word); |
318 | 363 | ||
319 | /* | 364 | /* |
320 | * Wait for command completion. | 365 | * Wait for command completion. |
@@ -338,18 +383,12 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) | |||
338 | 383 | ||
339 | static int hpc_check_cmd_status(struct controller *ctrl) | 384 | static int hpc_check_cmd_status(struct controller *ctrl) |
340 | { | 385 | { |
341 | struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; | ||
342 | u16 cmd_status; | 386 | u16 cmd_status; |
343 | int retval = 0; | 387 | int retval = 0; |
344 | 388 | ||
345 | DBG_ENTER_ROUTINE | 389 | DBG_ENTER_ROUTINE |
346 | |||
347 | if (!ctrl->hpc_ctlr_handle) { | ||
348 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | ||
349 | return -1; | ||
350 | } | ||
351 | 390 | ||
352 | cmd_status = readw(php_ctlr->creg + CMD_STATUS) & 0x000F; | 391 | cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F; |
353 | 392 | ||
354 | switch (cmd_status >> 1) { | 393 | switch (cmd_status >> 1) { |
355 | case 0: | 394 | case 0: |
@@ -378,37 +417,27 @@ static int hpc_check_cmd_status(struct controller *ctrl) | |||
378 | 417 | ||
379 | static int hpc_get_attention_status(struct slot *slot, u8 *status) | 418 | static int hpc_get_attention_status(struct slot *slot, u8 *status) |
380 | { | 419 | { |
381 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 420 | struct controller *ctrl = slot->ctrl; |
382 | u32 slot_reg; | 421 | u32 slot_reg; |
383 | u16 slot_status; | 422 | u8 state; |
384 | u8 atten_led_state; | ||
385 | 423 | ||
386 | DBG_ENTER_ROUTINE | 424 | DBG_ENTER_ROUTINE |
387 | 425 | ||
388 | if (!slot->ctrl->hpc_ctlr_handle) { | 426 | slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); |
389 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | 427 | state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT; |
390 | return -1; | ||
391 | } | ||
392 | |||
393 | slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); | ||
394 | slot_status = (u16) slot_reg; | ||
395 | atten_led_state = (slot_status & 0x0030) >> 4; | ||
396 | 428 | ||
397 | switch (atten_led_state) { | 429 | switch (state) { |
398 | case 0: | 430 | case ATN_LED_STATE_ON: |
399 | *status = 0xFF; /* Reserved */ | ||
400 | break; | ||
401 | case 1: | ||
402 | *status = 1; /* On */ | 431 | *status = 1; /* On */ |
403 | break; | 432 | break; |
404 | case 2: | 433 | case ATN_LED_STATE_BLINK: |
405 | *status = 2; /* Blink */ | 434 | *status = 2; /* Blink */ |
406 | break; | 435 | break; |
407 | case 3: | 436 | case ATN_LED_STATE_OFF: |
408 | *status = 0; /* Off */ | 437 | *status = 0; /* Off */ |
409 | break; | 438 | break; |
410 | default: | 439 | default: |
411 | *status = 0xFF; | 440 | *status = 0xFF; /* Reserved */ |
412 | break; | 441 | break; |
413 | } | 442 | } |
414 | 443 | ||
@@ -418,64 +447,44 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status) | |||
418 | 447 | ||
419 | static int hpc_get_power_status(struct slot * slot, u8 *status) | 448 | static int hpc_get_power_status(struct slot * slot, u8 *status) |
420 | { | 449 | { |
421 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 450 | struct controller *ctrl = slot->ctrl; |
422 | u32 slot_reg; | 451 | u32 slot_reg; |
423 | u16 slot_status; | 452 | u8 state; |
424 | u8 slot_state; | ||
425 | int retval = 0; | ||
426 | 453 | ||
427 | DBG_ENTER_ROUTINE | 454 | DBG_ENTER_ROUTINE |
428 | 455 | ||
429 | if (!slot->ctrl->hpc_ctlr_handle) { | 456 | slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); |
430 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | 457 | state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT; |
431 | return -1; | ||
432 | } | ||
433 | |||
434 | slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); | ||
435 | slot_status = (u16) slot_reg; | ||
436 | slot_state = (slot_status & 0x0003); | ||
437 | 458 | ||
438 | switch (slot_state) { | 459 | switch (state) { |
439 | case 0: | 460 | case SLOT_STATE_PWRONLY: |
440 | *status = 0xFF; | ||
441 | break; | ||
442 | case 1: | ||
443 | *status = 2; /* Powered only */ | 461 | *status = 2; /* Powered only */ |
444 | break; | 462 | break; |
445 | case 2: | 463 | case SLOT_STATE_ENABLED: |
446 | *status = 1; /* Enabled */ | 464 | *status = 1; /* Enabled */ |
447 | break; | 465 | break; |
448 | case 3: | 466 | case SLOT_STATE_DISABLED: |
449 | *status = 0; /* Disabled */ | 467 | *status = 0; /* Disabled */ |
450 | break; | 468 | break; |
451 | default: | 469 | default: |
452 | *status = 0xFF; | 470 | *status = 0xFF; /* Reserved */ |
453 | break; | 471 | break; |
454 | } | 472 | } |
455 | 473 | ||
456 | DBG_LEAVE_ROUTINE | 474 | DBG_LEAVE_ROUTINE |
457 | return retval; | 475 | return 0; |
458 | } | 476 | } |
459 | 477 | ||
460 | 478 | ||
461 | static int hpc_get_latch_status(struct slot *slot, u8 *status) | 479 | static int hpc_get_latch_status(struct slot *slot, u8 *status) |
462 | { | 480 | { |
463 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 481 | struct controller *ctrl = slot->ctrl; |
464 | u32 slot_reg; | 482 | u32 slot_reg; |
465 | u16 slot_status; | ||
466 | 483 | ||
467 | DBG_ENTER_ROUTINE | 484 | DBG_ENTER_ROUTINE |
468 | 485 | ||
469 | if (!slot->ctrl->hpc_ctlr_handle) { | 486 | slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); |
470 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | 487 | *status = !!(slot_reg & MRL_SENSOR); /* 0 -> close; 1 -> open */ |
471 | return -1; | ||
472 | } | ||
473 | |||
474 | slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); | ||
475 | slot_status = (u16)slot_reg; | ||
476 | |||
477 | *status = ((slot_status & 0x0100) == 0) ? 0 : 1; /* 0 -> close; 1 -> open */ | ||
478 | |||
479 | 488 | ||
480 | DBG_LEAVE_ROUTINE | 489 | DBG_LEAVE_ROUTINE |
481 | return 0; | 490 | return 0; |
@@ -483,22 +492,15 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status) | |||
483 | 492 | ||
484 | static int hpc_get_adapter_status(struct slot *slot, u8 *status) | 493 | static int hpc_get_adapter_status(struct slot *slot, u8 *status) |
485 | { | 494 | { |
486 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 495 | struct controller *ctrl = slot->ctrl; |
487 | u32 slot_reg; | 496 | u32 slot_reg; |
488 | u16 slot_status; | 497 | u8 state; |
489 | u8 card_state; | ||
490 | 498 | ||
491 | DBG_ENTER_ROUTINE | 499 | DBG_ENTER_ROUTINE |
492 | 500 | ||
493 | if (!slot->ctrl->hpc_ctlr_handle) { | 501 | slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); |
494 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | 502 | state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT; |
495 | return -1; | 503 | *status = (state != 0x3) ? 1 : 0; |
496 | } | ||
497 | |||
498 | slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); | ||
499 | slot_status = (u16)slot_reg; | ||
500 | card_state = (u8)((slot_status & 0x0C00) >> 10); | ||
501 | *status = (card_state != 0x3) ? 1 : 0; | ||
502 | 504 | ||
503 | DBG_LEAVE_ROUTINE | 505 | DBG_LEAVE_ROUTINE |
504 | return 0; | 506 | return 0; |
@@ -506,16 +508,11 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status) | |||
506 | 508 | ||
507 | static int hpc_get_prog_int(struct slot *slot, u8 *prog_int) | 509 | static int hpc_get_prog_int(struct slot *slot, u8 *prog_int) |
508 | { | 510 | { |
509 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 511 | struct controller *ctrl = slot->ctrl; |
510 | 512 | ||
511 | DBG_ENTER_ROUTINE | 513 | DBG_ENTER_ROUTINE |
512 | |||
513 | if (!slot->ctrl->hpc_ctlr_handle) { | ||
514 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | ||
515 | return -1; | ||
516 | } | ||
517 | 514 | ||
518 | *prog_int = readb(php_ctlr->creg + PROG_INTERFACE); | 515 | *prog_int = shpc_readb(ctrl, PROG_INTERFACE); |
519 | 516 | ||
520 | DBG_LEAVE_ROUTINE | 517 | DBG_LEAVE_ROUTINE |
521 | return 0; | 518 | return 0; |
@@ -524,13 +521,27 @@ static int hpc_get_prog_int(struct slot *slot, u8 *prog_int) | |||
524 | static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) | 521 | static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) |
525 | { | 522 | { |
526 | int retval = 0; | 523 | int retval = 0; |
527 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 524 | struct controller *ctrl = slot->ctrl; |
528 | u32 slot_reg = readl(php_ctlr->creg + SLOT1 + 4 * slot->hp_slot); | 525 | u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); |
529 | u8 pcix_cap = (slot_reg >> 12) & 7; | 526 | u8 m66_cap = !!(slot_reg & MHZ66_CAP); |
530 | u8 m66_cap = (slot_reg >> 9) & 1; | 527 | u8 pi, pcix_cap; |
531 | 528 | ||
532 | DBG_ENTER_ROUTINE | 529 | DBG_ENTER_ROUTINE |
533 | 530 | ||
531 | if ((retval = hpc_get_prog_int(slot, &pi))) | ||
532 | return retval; | ||
533 | |||
534 | switch (pi) { | ||
535 | case 1: | ||
536 | pcix_cap = (slot_reg & PCIX_CAP_MASK_PI1) >> PCIX_CAP_SHIFT; | ||
537 | break; | ||
538 | case 2: | ||
539 | pcix_cap = (slot_reg & PCIX_CAP_MASK_PI2) >> PCIX_CAP_SHIFT; | ||
540 | break; | ||
541 | default: | ||
542 | return -ENODEV; | ||
543 | } | ||
544 | |||
534 | dbg("%s: slot_reg = %x, pcix_cap = %x, m66_cap = %x\n", | 545 | dbg("%s: slot_reg = %x, pcix_cap = %x, m66_cap = %x\n", |
535 | __FUNCTION__, slot_reg, pcix_cap, m66_cap); | 546 | __FUNCTION__, slot_reg, pcix_cap, m66_cap); |
536 | 547 | ||
@@ -564,20 +575,15 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) | |||
564 | 575 | ||
565 | static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) | 576 | static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) |
566 | { | 577 | { |
567 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 578 | struct controller *ctrl = slot->ctrl; |
568 | u16 sec_bus_status; | 579 | u16 sec_bus_status; |
569 | u8 pi; | 580 | u8 pi; |
570 | int retval = 0; | 581 | int retval = 0; |
571 | 582 | ||
572 | DBG_ENTER_ROUTINE | 583 | DBG_ENTER_ROUTINE |
573 | 584 | ||
574 | if (!slot->ctrl->hpc_ctlr_handle) { | 585 | pi = shpc_readb(ctrl, PROG_INTERFACE); |
575 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | 586 | sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG); |
576 | return -1; | ||
577 | } | ||
578 | |||
579 | pi = readb(php_ctlr->creg + PROG_INTERFACE); | ||
580 | sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG); | ||
581 | 587 | ||
582 | if (pi == 2) { | 588 | if (pi == 2) { |
583 | *mode = (sec_bus_status & 0x0100) >> 8; | 589 | *mode = (sec_bus_status & 0x0100) >> 8; |
@@ -593,128 +599,53 @@ static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) | |||
593 | 599 | ||
594 | static int hpc_query_power_fault(struct slot * slot) | 600 | static int hpc_query_power_fault(struct slot * slot) |
595 | { | 601 | { |
596 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 602 | struct controller *ctrl = slot->ctrl; |
597 | u32 slot_reg; | 603 | u32 slot_reg; |
598 | u16 slot_status; | ||
599 | u8 pwr_fault_state, status; | ||
600 | 604 | ||
601 | DBG_ENTER_ROUTINE | 605 | DBG_ENTER_ROUTINE |
602 | 606 | ||
603 | if (!slot->ctrl->hpc_ctlr_handle) { | 607 | slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); |
604 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | ||
605 | return -1; | ||
606 | } | ||
607 | |||
608 | slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); | ||
609 | slot_status = (u16) slot_reg; | ||
610 | pwr_fault_state = (slot_status & 0x0040) >> 7; | ||
611 | status = (pwr_fault_state == 1) ? 0 : 1; | ||
612 | 608 | ||
613 | DBG_LEAVE_ROUTINE | 609 | DBG_LEAVE_ROUTINE |
614 | /* Note: Logic 0 => fault */ | 610 | /* Note: Logic 0 => fault */ |
615 | return status; | 611 | return !(slot_reg & POWER_FAULT); |
616 | } | 612 | } |
617 | 613 | ||
618 | static int hpc_set_attention_status(struct slot *slot, u8 value) | 614 | static int hpc_set_attention_status(struct slot *slot, u8 value) |
619 | { | 615 | { |
620 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | ||
621 | u8 slot_cmd = 0; | 616 | u8 slot_cmd = 0; |
622 | int rc = 0; | ||
623 | |||
624 | if (!slot->ctrl->hpc_ctlr_handle) { | ||
625 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | ||
626 | return -1; | ||
627 | } | ||
628 | |||
629 | if (slot->hp_slot >= php_ctlr->num_slots) { | ||
630 | err("%s: Invalid HPC slot number!\n", __FUNCTION__); | ||
631 | return -1; | ||
632 | } | ||
633 | 617 | ||
634 | switch (value) { | 618 | switch (value) { |
635 | case 0 : | 619 | case 0 : |
636 | slot_cmd = 0x30; /* OFF */ | 620 | slot_cmd = SET_ATTN_OFF; /* OFF */ |
637 | break; | 621 | break; |
638 | case 1: | 622 | case 1: |
639 | slot_cmd = 0x10; /* ON */ | 623 | slot_cmd = SET_ATTN_ON; /* ON */ |
640 | break; | 624 | break; |
641 | case 2: | 625 | case 2: |
642 | slot_cmd = 0x20; /* BLINK */ | 626 | slot_cmd = SET_ATTN_BLINK; /* BLINK */ |
643 | break; | 627 | break; |
644 | default: | 628 | default: |
645 | return -1; | 629 | return -1; |
646 | } | 630 | } |
647 | 631 | ||
648 | shpc_write_cmd(slot, slot->hp_slot, slot_cmd); | 632 | return shpc_write_cmd(slot, slot->hp_slot, slot_cmd); |
649 | |||
650 | return rc; | ||
651 | } | 633 | } |
652 | 634 | ||
653 | 635 | ||
654 | static void hpc_set_green_led_on(struct slot *slot) | 636 | static void hpc_set_green_led_on(struct slot *slot) |
655 | { | 637 | { |
656 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 638 | shpc_write_cmd(slot, slot->hp_slot, SET_PWR_ON); |
657 | u8 slot_cmd; | ||
658 | |||
659 | if (!slot->ctrl->hpc_ctlr_handle) { | ||
660 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | ||
661 | return ; | ||
662 | } | ||
663 | |||
664 | if (slot->hp_slot >= php_ctlr->num_slots) { | ||
665 | err("%s: Invalid HPC slot number!\n", __FUNCTION__); | ||
666 | return ; | ||
667 | } | ||
668 | |||
669 | slot_cmd = 0x04; | ||
670 | |||
671 | shpc_write_cmd(slot, slot->hp_slot, slot_cmd); | ||
672 | |||
673 | return; | ||
674 | } | 639 | } |
675 | 640 | ||
676 | static void hpc_set_green_led_off(struct slot *slot) | 641 | static void hpc_set_green_led_off(struct slot *slot) |
677 | { | 642 | { |
678 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 643 | shpc_write_cmd(slot, slot->hp_slot, SET_PWR_OFF); |
679 | u8 slot_cmd; | ||
680 | |||
681 | if (!slot->ctrl->hpc_ctlr_handle) { | ||
682 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | ||
683 | return ; | ||
684 | } | ||
685 | |||
686 | if (slot->hp_slot >= php_ctlr->num_slots) { | ||
687 | err("%s: Invalid HPC slot number!\n", __FUNCTION__); | ||
688 | return ; | ||
689 | } | ||
690 | |||
691 | slot_cmd = 0x0C; | ||
692 | |||
693 | shpc_write_cmd(slot, slot->hp_slot, slot_cmd); | ||
694 | |||
695 | return; | ||
696 | } | 644 | } |
697 | 645 | ||
698 | static void hpc_set_green_led_blink(struct slot *slot) | 646 | static void hpc_set_green_led_blink(struct slot *slot) |
699 | { | 647 | { |
700 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 648 | shpc_write_cmd(slot, slot->hp_slot, SET_PWR_BLINK); |
701 | u8 slot_cmd; | ||
702 | |||
703 | if (!slot->ctrl->hpc_ctlr_handle) { | ||
704 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | ||
705 | return ; | ||
706 | } | ||
707 | |||
708 | if (slot->hp_slot >= php_ctlr->num_slots) { | ||
709 | err("%s: Invalid HPC slot number!\n", __FUNCTION__); | ||
710 | return ; | ||
711 | } | ||
712 | |||
713 | slot_cmd = 0x08; | ||
714 | |||
715 | shpc_write_cmd(slot, slot->hp_slot, slot_cmd); | ||
716 | |||
717 | return; | ||
718 | } | 649 | } |
719 | 650 | ||
720 | int shpc_get_ctlr_slot_config(struct controller *ctrl, | 651 | int shpc_get_ctlr_slot_config(struct controller *ctrl, |
@@ -724,21 +655,17 @@ int shpc_get_ctlr_slot_config(struct controller *ctrl, | |||
724 | int *updown, /* physical_slot_num increament: 1 or -1 */ | 655 | int *updown, /* physical_slot_num increament: 1 or -1 */ |
725 | int *flags) | 656 | int *flags) |
726 | { | 657 | { |
727 | struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; | 658 | u32 slot_config; |
728 | 659 | ||
729 | DBG_ENTER_ROUTINE | 660 | DBG_ENTER_ROUTINE |
730 | 661 | ||
731 | if (!ctrl->hpc_ctlr_handle) { | 662 | slot_config = shpc_readl(ctrl, SLOT_CONFIG); |
732 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | 663 | *first_device_num = (slot_config & FIRST_DEV_NUM) >> 8; |
733 | return -1; | 664 | *num_ctlr_slots = slot_config & SLOT_NUM; |
734 | } | 665 | *physical_slot_num = (slot_config & PSN) >> 16; |
735 | 666 | *updown = ((slot_config & UPDOWN) >> 29) ? 1 : -1; | |
736 | *first_device_num = php_ctlr->slot_device_offset; /* Obtained in shpc_init() */ | ||
737 | *num_ctlr_slots = php_ctlr->num_slots; /* Obtained in shpc_init() */ | ||
738 | 667 | ||
739 | *physical_slot_num = (readl(php_ctlr->creg + SLOT_CONFIG) & PSN) >> 16; | ||
740 | dbg("%s: physical_slot_num = %x\n", __FUNCTION__, *physical_slot_num); | 668 | dbg("%s: physical_slot_num = %x\n", __FUNCTION__, *physical_slot_num); |
741 | *updown = ((readl(php_ctlr->creg + SLOT_CONFIG) & UPDOWN ) >> 29) ? 1 : -1; | ||
742 | 669 | ||
743 | DBG_LEAVE_ROUTINE | 670 | DBG_LEAVE_ROUTINE |
744 | return 0; | 671 | return 0; |
@@ -749,22 +676,34 @@ static void hpc_release_ctlr(struct controller *ctrl) | |||
749 | struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; | 676 | struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; |
750 | struct php_ctlr_state_s *p, *p_prev; | 677 | struct php_ctlr_state_s *p, *p_prev; |
751 | int i; | 678 | int i; |
679 | u32 slot_reg, serr_int; | ||
752 | 680 | ||
753 | DBG_ENTER_ROUTINE | 681 | DBG_ENTER_ROUTINE |
754 | 682 | ||
755 | if (!ctrl->hpc_ctlr_handle) { | ||
756 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | ||
757 | return ; | ||
758 | } | ||
759 | |||
760 | /* | 683 | /* |
761 | * Mask all slot event interrupts | 684 | * Mask event interrupts and SERRs of all slots |
762 | */ | 685 | */ |
763 | for (i = 0; i < ctrl->num_slots; i++) | 686 | for (i = 0; i < ctrl->num_slots; i++) { |
764 | writel(0xffff3fff, php_ctlr->creg + SLOT1 + (4 * i)); | 687 | slot_reg = shpc_readl(ctrl, SLOT_REG(i)); |
688 | slot_reg |= (PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK | | ||
689 | BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK | | ||
690 | CON_PFAULT_INTR_MASK | MRL_CHANGE_SERR_MASK | | ||
691 | CON_PFAULT_SERR_MASK); | ||
692 | slot_reg &= ~SLOT_REG_RSVDZ_MASK; | ||
693 | shpc_writel(ctrl, SLOT_REG(i), slot_reg); | ||
694 | } | ||
765 | 695 | ||
766 | cleanup_slots(ctrl); | 696 | cleanup_slots(ctrl); |
767 | 697 | ||
698 | /* | ||
699 | * Mask SERR and System Interrut generation | ||
700 | */ | ||
701 | serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); | ||
702 | serr_int |= (GLOBAL_INTR_MASK | GLOBAL_SERR_MASK | | ||
703 | COMMAND_INTR_MASK | ARBITER_SERR_MASK); | ||
704 | serr_int &= ~SERR_INTR_RSVDZ_MASK; | ||
705 | shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); | ||
706 | |||
768 | if (shpchp_poll_mode) { | 707 | if (shpchp_poll_mode) { |
769 | del_timer(&php_ctlr->int_poll_timer); | 708 | del_timer(&php_ctlr->int_poll_timer); |
770 | } else { | 709 | } else { |
@@ -800,113 +739,79 @@ static void hpc_release_ctlr(struct controller *ctrl) | |||
800 | 739 | ||
801 | kfree(php_ctlr); | 740 | kfree(php_ctlr); |
802 | 741 | ||
742 | /* | ||
743 | * If this is the last controller to be released, destroy the | ||
744 | * shpchpd work queue | ||
745 | */ | ||
746 | if (atomic_dec_and_test(&shpchp_num_controllers)) | ||
747 | destroy_workqueue(shpchp_wq); | ||
748 | |||
803 | DBG_LEAVE_ROUTINE | 749 | DBG_LEAVE_ROUTINE |
804 | 750 | ||
805 | } | 751 | } |
806 | 752 | ||
807 | static int hpc_power_on_slot(struct slot * slot) | 753 | static int hpc_power_on_slot(struct slot * slot) |
808 | { | 754 | { |
809 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 755 | int retval; |
810 | u8 slot_cmd; | ||
811 | int retval = 0; | ||
812 | 756 | ||
813 | DBG_ENTER_ROUTINE | 757 | DBG_ENTER_ROUTINE |
814 | 758 | ||
815 | if (!slot->ctrl->hpc_ctlr_handle) { | 759 | retval = shpc_write_cmd(slot, slot->hp_slot, SET_SLOT_PWR); |
816 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | ||
817 | return -1; | ||
818 | } | ||
819 | |||
820 | if (slot->hp_slot >= php_ctlr->num_slots) { | ||
821 | err("%s: Invalid HPC slot number!\n", __FUNCTION__); | ||
822 | return -1; | ||
823 | } | ||
824 | slot_cmd = 0x01; | ||
825 | |||
826 | retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd); | ||
827 | |||
828 | if (retval) { | 760 | if (retval) { |
829 | err("%s: Write command failed!\n", __FUNCTION__); | 761 | err("%s: Write command failed!\n", __FUNCTION__); |
830 | return -1; | 762 | return retval; |
831 | } | 763 | } |
832 | 764 | ||
833 | DBG_LEAVE_ROUTINE | 765 | DBG_LEAVE_ROUTINE |
834 | 766 | ||
835 | return retval; | 767 | return 0; |
836 | } | 768 | } |
837 | 769 | ||
838 | static int hpc_slot_enable(struct slot * slot) | 770 | static int hpc_slot_enable(struct slot * slot) |
839 | { | 771 | { |
840 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 772 | int retval; |
841 | u8 slot_cmd; | ||
842 | int retval = 0; | ||
843 | 773 | ||
844 | DBG_ENTER_ROUTINE | 774 | DBG_ENTER_ROUTINE |
845 | 775 | ||
846 | if (!slot->ctrl->hpc_ctlr_handle) { | 776 | /* Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */ |
847 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | 777 | retval = shpc_write_cmd(slot, slot->hp_slot, |
848 | return -1; | 778 | SET_SLOT_ENABLE | SET_PWR_BLINK | SET_ATTN_OFF); |
849 | } | ||
850 | |||
851 | if (slot->hp_slot >= php_ctlr->num_slots) { | ||
852 | err("%s: Invalid HPC slot number!\n", __FUNCTION__); | ||
853 | return -1; | ||
854 | } | ||
855 | /* 3A => Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */ | ||
856 | slot_cmd = 0x3A; | ||
857 | |||
858 | retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd); | ||
859 | |||
860 | if (retval) { | 779 | if (retval) { |
861 | err("%s: Write command failed!\n", __FUNCTION__); | 780 | err("%s: Write command failed!\n", __FUNCTION__); |
862 | return -1; | 781 | return retval; |
863 | } | 782 | } |
864 | 783 | ||
865 | DBG_LEAVE_ROUTINE | 784 | DBG_LEAVE_ROUTINE |
866 | return retval; | 785 | return 0; |
867 | } | 786 | } |
868 | 787 | ||
869 | static int hpc_slot_disable(struct slot * slot) | 788 | static int hpc_slot_disable(struct slot * slot) |
870 | { | 789 | { |
871 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 790 | int retval; |
872 | u8 slot_cmd; | ||
873 | int retval = 0; | ||
874 | 791 | ||
875 | DBG_ENTER_ROUTINE | 792 | DBG_ENTER_ROUTINE |
876 | 793 | ||
877 | if (!slot->ctrl->hpc_ctlr_handle) { | 794 | /* Slot - Disable, Power Indicator - Off, Attention Indicator - On */ |
878 | err("%s: Invalid HPC controller handle!\n", __FUNCTION__); | 795 | retval = shpc_write_cmd(slot, slot->hp_slot, |
879 | return -1; | 796 | SET_SLOT_DISABLE | SET_PWR_OFF | SET_ATTN_ON); |
880 | } | ||
881 | |||
882 | if (slot->hp_slot >= php_ctlr->num_slots) { | ||
883 | err("%s: Invalid HPC slot number!\n", __FUNCTION__); | ||
884 | return -1; | ||
885 | } | ||
886 | |||
887 | /* 1F => Slot - Disable, Power Indicator - Off, Attention Indicator - On */ | ||
888 | slot_cmd = 0x1F; | ||
889 | |||
890 | retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd); | ||
891 | |||
892 | if (retval) { | 797 | if (retval) { |
893 | err("%s: Write command failed!\n", __FUNCTION__); | 798 | err("%s: Write command failed!\n", __FUNCTION__); |
894 | return -1; | 799 | return retval; |
895 | } | 800 | } |
896 | 801 | ||
897 | DBG_LEAVE_ROUTINE | 802 | DBG_LEAVE_ROUTINE |
898 | return retval; | 803 | return 0; |
899 | } | 804 | } |
900 | 805 | ||
901 | static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) | 806 | static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) |
902 | { | 807 | { |
903 | int retval; | 808 | int retval; |
904 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 809 | struct controller *ctrl = slot->ctrl; |
905 | u8 pi, cmd; | 810 | u8 pi, cmd; |
906 | 811 | ||
907 | DBG_ENTER_ROUTINE | 812 | DBG_ENTER_ROUTINE |
908 | 813 | ||
909 | pi = readb(php_ctlr->creg + PROG_INTERFACE); | 814 | pi = shpc_readb(ctrl, PROG_INTERFACE); |
910 | if ((pi == 1) && (value > PCI_SPEED_133MHz_PCIX)) | 815 | if ((pi == 1) && (value > PCI_SPEED_133MHz_PCIX)) |
911 | return -EINVAL; | 816 | return -EINVAL; |
912 | 817 | ||
@@ -965,100 +870,86 @@ static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) | |||
965 | return retval; | 870 | return retval; |
966 | } | 871 | } |
967 | 872 | ||
968 | static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) | 873 | static irqreturn_t shpc_isr(int irq, void *dev_id, struct pt_regs *regs) |
969 | { | 874 | { |
970 | struct controller *ctrl = NULL; | 875 | struct controller *ctrl = (struct controller *)dev_id; |
971 | struct php_ctlr_state_s *php_ctlr; | 876 | struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; |
972 | u8 schedule_flag = 0; | 877 | u32 serr_int, slot_reg, intr_loc, intr_loc2; |
973 | u8 temp_byte; | ||
974 | u32 temp_dword, intr_loc, intr_loc2; | ||
975 | int hp_slot; | 878 | int hp_slot; |
976 | 879 | ||
977 | if (!dev_id) | ||
978 | return IRQ_NONE; | ||
979 | |||
980 | if (!shpchp_poll_mode) { | ||
981 | ctrl = (struct controller *)dev_id; | ||
982 | php_ctlr = ctrl->hpc_ctlr_handle; | ||
983 | } else { | ||
984 | php_ctlr = (struct php_ctlr_state_s *) dev_id; | ||
985 | ctrl = (struct controller *)php_ctlr->callback_instance_id; | ||
986 | } | ||
987 | |||
988 | if (!ctrl) | ||
989 | return IRQ_NONE; | ||
990 | |||
991 | if (!php_ctlr || !php_ctlr->creg) | ||
992 | return IRQ_NONE; | ||
993 | |||
994 | /* Check to see if it was our interrupt */ | 880 | /* Check to see if it was our interrupt */ |
995 | intr_loc = readl(php_ctlr->creg + INTR_LOC); | 881 | intr_loc = shpc_readl(ctrl, INTR_LOC); |
996 | |||
997 | if (!intr_loc) | 882 | if (!intr_loc) |
998 | return IRQ_NONE; | 883 | return IRQ_NONE; |
884 | |||
999 | dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc); | 885 | dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc); |
1000 | 886 | ||
1001 | if(!shpchp_poll_mode) { | 887 | if(!shpchp_poll_mode) { |
1002 | /* Mask Global Interrupt Mask - see implementation note on p. 139 */ | 888 | /* |
1003 | /* of SHPC spec rev 1.0*/ | 889 | * Mask Global Interrupt Mask - see implementation |
1004 | temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); | 890 | * note on p. 139 of SHPC spec rev 1.0 |
1005 | temp_dword |= 0x00000001; | 891 | */ |
1006 | writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); | 892 | serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); |
893 | serr_int |= GLOBAL_INTR_MASK; | ||
894 | serr_int &= ~SERR_INTR_RSVDZ_MASK; | ||
895 | shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); | ||
1007 | 896 | ||
1008 | intr_loc2 = readl(php_ctlr->creg + INTR_LOC); | 897 | intr_loc2 = shpc_readl(ctrl, INTR_LOC); |
1009 | dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); | 898 | dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); |
1010 | } | 899 | } |
1011 | 900 | ||
1012 | if (intr_loc & 0x0001) { | 901 | if (intr_loc & CMD_INTR_PENDING) { |
1013 | /* | 902 | /* |
1014 | * Command Complete Interrupt Pending | 903 | * Command Complete Interrupt Pending |
1015 | * RO only - clear by writing 1 to the Command Completion | 904 | * RO only - clear by writing 1 to the Command Completion |
1016 | * Detect bit in Controller SERR-INT register | 905 | * Detect bit in Controller SERR-INT register |
1017 | */ | 906 | */ |
1018 | temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); | 907 | serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); |
1019 | temp_dword &= 0xfffdffff; | 908 | serr_int &= ~SERR_INTR_RSVDZ_MASK; |
1020 | writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); | 909 | shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); |
910 | |||
1021 | ctrl->cmd_busy = 0; | 911 | ctrl->cmd_busy = 0; |
1022 | wake_up_interruptible(&ctrl->queue); | 912 | wake_up_interruptible(&ctrl->queue); |
1023 | } | 913 | } |
1024 | 914 | ||
1025 | if ((intr_loc = (intr_loc >> 1)) == 0) | 915 | if (!(intr_loc & ~CMD_INTR_PENDING)) |
1026 | goto out; | 916 | goto out; |
1027 | 917 | ||
1028 | for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { | 918 | for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { |
1029 | /* To find out which slot has interrupt pending */ | 919 | /* To find out which slot has interrupt pending */ |
1030 | if ((intr_loc >> hp_slot) & 0x01) { | 920 | if (!(intr_loc & SLOT_INTR_PENDING(hp_slot))) |
1031 | temp_dword = readl(php_ctlr->creg + SLOT1 + (4*hp_slot)); | 921 | continue; |
1032 | dbg("%s: Slot %x with intr, slot register = %x\n", | 922 | |
1033 | __FUNCTION__, hp_slot, temp_dword); | 923 | slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); |
1034 | temp_byte = (temp_dword >> 16) & 0xFF; | 924 | dbg("%s: Slot %x with intr, slot register = %x\n", |
1035 | if ((php_ctlr->switch_change_callback) && (temp_byte & 0x08)) | 925 | __FUNCTION__, hp_slot, slot_reg); |
1036 | schedule_flag += php_ctlr->switch_change_callback( | 926 | |
1037 | hp_slot, php_ctlr->callback_instance_id); | 927 | if (slot_reg & MRL_CHANGE_DETECTED) |
1038 | if ((php_ctlr->attention_button_callback) && (temp_byte & 0x04)) | 928 | php_ctlr->switch_change_callback( |
1039 | schedule_flag += php_ctlr->attention_button_callback( | 929 | hp_slot, php_ctlr->callback_instance_id); |
1040 | hp_slot, php_ctlr->callback_instance_id); | 930 | |
1041 | if ((php_ctlr->presence_change_callback) && (temp_byte & 0x01)) | 931 | if (slot_reg & BUTTON_PRESS_DETECTED) |
1042 | schedule_flag += php_ctlr->presence_change_callback( | 932 | php_ctlr->attention_button_callback( |
1043 | hp_slot , php_ctlr->callback_instance_id); | 933 | hp_slot, php_ctlr->callback_instance_id); |
1044 | if ((php_ctlr->power_fault_callback) && (temp_byte & 0x12)) | 934 | |
1045 | schedule_flag += php_ctlr->power_fault_callback( | 935 | if (slot_reg & PRSNT_CHANGE_DETECTED) |
1046 | hp_slot, php_ctlr->callback_instance_id); | 936 | php_ctlr->presence_change_callback( |
1047 | 937 | hp_slot , php_ctlr->callback_instance_id); | |
1048 | /* Clear all slot events */ | 938 | |
1049 | temp_dword = 0xe01f3fff; | 939 | if (slot_reg & (ISO_PFAULT_DETECTED | CON_PFAULT_DETECTED)) |
1050 | writel(temp_dword, php_ctlr->creg + SLOT1 + (4*hp_slot)); | 940 | php_ctlr->power_fault_callback( |
1051 | 941 | hp_slot, php_ctlr->callback_instance_id); | |
1052 | intr_loc2 = readl(php_ctlr->creg + INTR_LOC); | 942 | |
1053 | dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); | 943 | /* Clear all slot events */ |
1054 | } | 944 | slot_reg &= ~SLOT_REG_RSVDZ_MASK; |
945 | shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg); | ||
1055 | } | 946 | } |
1056 | out: | 947 | out: |
1057 | if (!shpchp_poll_mode) { | 948 | if (!shpchp_poll_mode) { |
1058 | /* Unmask Global Interrupt Mask */ | 949 | /* Unmask Global Interrupt Mask */ |
1059 | temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); | 950 | serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); |
1060 | temp_dword &= 0xfffffffe; | 951 | serr_int &= ~(GLOBAL_INTR_MASK | SERR_INTR_RSVDZ_MASK); |
1061 | writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); | 952 | shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); |
1062 | } | 953 | } |
1063 | 954 | ||
1064 | return IRQ_HANDLED; | 955 | return IRQ_HANDLED; |
@@ -1067,11 +958,11 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) | |||
1067 | static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value) | 958 | static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value) |
1068 | { | 959 | { |
1069 | int retval = 0; | 960 | int retval = 0; |
1070 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 961 | struct controller *ctrl = slot->ctrl; |
1071 | enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; | 962 | enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; |
1072 | u8 pi = readb(php_ctlr->creg + PROG_INTERFACE); | 963 | u8 pi = shpc_readb(ctrl, PROG_INTERFACE); |
1073 | u32 slot_avail1 = readl(php_ctlr->creg + SLOT_AVAIL1); | 964 | u32 slot_avail1 = shpc_readl(ctrl, SLOT_AVAIL1); |
1074 | u32 slot_avail2 = readl(php_ctlr->creg + SLOT_AVAIL2); | 965 | u32 slot_avail2 = shpc_readl(ctrl, SLOT_AVAIL2); |
1075 | 966 | ||
1076 | DBG_ENTER_ROUTINE | 967 | DBG_ENTER_ROUTINE |
1077 | 968 | ||
@@ -1114,10 +1005,10 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value) | |||
1114 | static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value) | 1005 | static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value) |
1115 | { | 1006 | { |
1116 | int retval = 0; | 1007 | int retval = 0; |
1117 | struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; | 1008 | struct controller *ctrl = slot->ctrl; |
1118 | enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; | 1009 | enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; |
1119 | u16 sec_bus_reg = readw(php_ctlr->creg + SEC_BUS_CONFIG); | 1010 | u16 sec_bus_reg = shpc_readw(ctrl, SEC_BUS_CONFIG); |
1120 | u8 pi = readb(php_ctlr->creg + PROG_INTERFACE); | 1011 | u8 pi = shpc_readb(ctrl, PROG_INTERFACE); |
1121 | u8 speed_mode = (pi == 2) ? (sec_bus_reg & 0xF) : (sec_bus_reg & 0x7); | 1012 | u8 speed_mode = (pi == 2) ? (sec_bus_reg & 0xF) : (sec_bus_reg & 0x7); |
1122 | 1013 | ||
1123 | DBG_ENTER_ROUTINE | 1014 | DBG_ENTER_ROUTINE |
@@ -1206,28 +1097,14 @@ static struct hpc_ops shpchp_hpc_ops = { | |||
1206 | .release_ctlr = hpc_release_ctlr, | 1097 | .release_ctlr = hpc_release_ctlr, |
1207 | }; | 1098 | }; |
1208 | 1099 | ||
1209 | inline static int shpc_indirect_creg_read(struct controller *ctrl, int index, | ||
1210 | u32 *value) | ||
1211 | { | ||
1212 | int rc; | ||
1213 | u32 cap_offset = ctrl->cap_offset; | ||
1214 | struct pci_dev *pdev = ctrl->pci_dev; | ||
1215 | |||
1216 | rc = pci_write_config_byte(pdev, cap_offset + DWORD_SELECT, index); | ||
1217 | if (rc) | ||
1218 | return rc; | ||
1219 | return pci_read_config_dword(pdev, cap_offset + DWORD_DATA, value); | ||
1220 | } | ||
1221 | |||
1222 | int shpc_init(struct controller * ctrl, struct pci_dev * pdev) | 1100 | int shpc_init(struct controller * ctrl, struct pci_dev * pdev) |
1223 | { | 1101 | { |
1224 | struct php_ctlr_state_s *php_ctlr, *p; | 1102 | struct php_ctlr_state_s *php_ctlr, *p; |
1225 | void *instance_id = ctrl; | 1103 | void *instance_id = ctrl; |
1226 | int rc, num_slots = 0; | 1104 | int rc, num_slots = 0; |
1227 | u8 hp_slot; | 1105 | u8 hp_slot; |
1228 | static int first = 1; | ||
1229 | u32 shpc_base_offset; | 1106 | u32 shpc_base_offset; |
1230 | u32 tempdword, slot_reg; | 1107 | u32 tempdword, slot_reg, slot_config; |
1231 | u8 i; | 1108 | u8 i; |
1232 | 1109 | ||
1233 | DBG_ENTER_ROUTINE | 1110 | DBG_ENTER_ROUTINE |
@@ -1257,13 +1134,13 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) | |||
1257 | } | 1134 | } |
1258 | dbg("%s: cap_offset = %x\n", __FUNCTION__, ctrl->cap_offset); | 1135 | dbg("%s: cap_offset = %x\n", __FUNCTION__, ctrl->cap_offset); |
1259 | 1136 | ||
1260 | rc = shpc_indirect_creg_read(ctrl, 0, &shpc_base_offset); | 1137 | rc = shpc_indirect_read(ctrl, 0, &shpc_base_offset); |
1261 | if (rc) { | 1138 | if (rc) { |
1262 | err("%s: cannot read base_offset\n", __FUNCTION__); | 1139 | err("%s: cannot read base_offset\n", __FUNCTION__); |
1263 | goto abort_free_ctlr; | 1140 | goto abort_free_ctlr; |
1264 | } | 1141 | } |
1265 | 1142 | ||
1266 | rc = shpc_indirect_creg_read(ctrl, 3, &tempdword); | 1143 | rc = shpc_indirect_read(ctrl, 3, &tempdword); |
1267 | if (rc) { | 1144 | if (rc) { |
1268 | err("%s: cannot read slot config\n", __FUNCTION__); | 1145 | err("%s: cannot read slot config\n", __FUNCTION__); |
1269 | goto abort_free_ctlr; | 1146 | goto abort_free_ctlr; |
@@ -1272,7 +1149,7 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) | |||
1272 | dbg("%s: num_slots (indirect) %x\n", __FUNCTION__, num_slots); | 1149 | dbg("%s: num_slots (indirect) %x\n", __FUNCTION__, num_slots); |
1273 | 1150 | ||
1274 | for (i = 0; i < 9 + num_slots; i++) { | 1151 | for (i = 0; i < 9 + num_slots; i++) { |
1275 | rc = shpc_indirect_creg_read(ctrl, i, &tempdword); | 1152 | rc = shpc_indirect_read(ctrl, i, &tempdword); |
1276 | if (rc) { | 1153 | if (rc) { |
1277 | err("%s: cannot read creg (index = %d)\n", | 1154 | err("%s: cannot read creg (index = %d)\n", |
1278 | __FUNCTION__, i); | 1155 | __FUNCTION__, i); |
@@ -1287,11 +1164,6 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) | |||
1287 | ctrl->mmio_size = 0x24 + 0x4 * num_slots; | 1164 | ctrl->mmio_size = 0x24 + 0x4 * num_slots; |
1288 | } | 1165 | } |
1289 | 1166 | ||
1290 | if (first) { | ||
1291 | spin_lock_init(&hpc_event_lock); | ||
1292 | first = 0; | ||
1293 | } | ||
1294 | |||
1295 | info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, | 1167 | info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, |
1296 | pdev->subsystem_device); | 1168 | pdev->subsystem_device); |
1297 | 1169 | ||
@@ -1326,29 +1198,39 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) | |||
1326 | php_ctlr->power_fault_callback = shpchp_handle_power_fault; | 1198 | php_ctlr->power_fault_callback = shpchp_handle_power_fault; |
1327 | php_ctlr->callback_instance_id = instance_id; | 1199 | php_ctlr->callback_instance_id = instance_id; |
1328 | 1200 | ||
1201 | ctrl->hpc_ctlr_handle = php_ctlr; | ||
1202 | ctrl->hpc_ops = &shpchp_hpc_ops; | ||
1203 | |||
1329 | /* Return PCI Controller Info */ | 1204 | /* Return PCI Controller Info */ |
1330 | php_ctlr->slot_device_offset = (readl(php_ctlr->creg + SLOT_CONFIG) & FIRST_DEV_NUM ) >> 8; | 1205 | slot_config = shpc_readl(ctrl, SLOT_CONFIG); |
1331 | php_ctlr->num_slots = readl(php_ctlr->creg + SLOT_CONFIG) & SLOT_NUM; | 1206 | php_ctlr->slot_device_offset = (slot_config & FIRST_DEV_NUM) >> 8; |
1207 | php_ctlr->num_slots = slot_config & SLOT_NUM; | ||
1332 | dbg("%s: slot_device_offset %x\n", __FUNCTION__, php_ctlr->slot_device_offset); | 1208 | dbg("%s: slot_device_offset %x\n", __FUNCTION__, php_ctlr->slot_device_offset); |
1333 | dbg("%s: num_slots %x\n", __FUNCTION__, php_ctlr->num_slots); | 1209 | dbg("%s: num_slots %x\n", __FUNCTION__, php_ctlr->num_slots); |
1334 | 1210 | ||
1335 | /* Mask Global Interrupt Mask & Command Complete Interrupt Mask */ | 1211 | /* Mask Global Interrupt Mask & Command Complete Interrupt Mask */ |
1336 | tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE); | 1212 | tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); |
1337 | dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); | 1213 | dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); |
1338 | tempdword = 0x0003000f; | 1214 | tempdword |= (GLOBAL_INTR_MASK | GLOBAL_SERR_MASK | |
1339 | writel(tempdword, php_ctlr->creg + SERR_INTR_ENABLE); | 1215 | COMMAND_INTR_MASK | ARBITER_SERR_MASK); |
1340 | tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE); | 1216 | tempdword &= ~SERR_INTR_RSVDZ_MASK; |
1217 | shpc_writel(ctrl, SERR_INTR_ENABLE, tempdword); | ||
1218 | tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); | ||
1341 | dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); | 1219 | dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); |
1342 | 1220 | ||
1343 | /* Mask the MRL sensor SERR Mask of individual slot in | 1221 | /* Mask the MRL sensor SERR Mask of individual slot in |
1344 | * Slot SERR-INT Mask & clear all the existing event if any | 1222 | * Slot SERR-INT Mask & clear all the existing event if any |
1345 | */ | 1223 | */ |
1346 | for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { | 1224 | for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { |
1347 | slot_reg = readl(php_ctlr->creg + SLOT1 + 4*hp_slot ); | 1225 | slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); |
1348 | dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, | 1226 | dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, |
1349 | hp_slot, slot_reg); | 1227 | hp_slot, slot_reg); |
1350 | tempdword = 0xffff3fff; | 1228 | slot_reg |= (PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK | |
1351 | writel(tempdword, php_ctlr->creg + SLOT1 + (4*hp_slot)); | 1229 | BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK | |
1230 | CON_PFAULT_INTR_MASK | MRL_CHANGE_SERR_MASK | | ||
1231 | CON_PFAULT_SERR_MASK); | ||
1232 | slot_reg &= ~SLOT_REG_RSVDZ_MASK; | ||
1233 | shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg); | ||
1352 | } | 1234 | } |
1353 | 1235 | ||
1354 | if (shpchp_poll_mode) {/* Install interrupt polling code */ | 1236 | if (shpchp_poll_mode) {/* Install interrupt polling code */ |
@@ -1392,24 +1274,37 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) | |||
1392 | } | 1274 | } |
1393 | spin_unlock(&list_lock); | 1275 | spin_unlock(&list_lock); |
1394 | 1276 | ||
1395 | |||
1396 | ctlr_seq_num++; | 1277 | ctlr_seq_num++; |
1397 | ctrl->hpc_ctlr_handle = php_ctlr; | ||
1398 | ctrl->hpc_ops = &shpchp_hpc_ops; | ||
1399 | 1278 | ||
1279 | /* | ||
1280 | * If this is the first controller to be initialized, | ||
1281 | * initialize the shpchpd work queue | ||
1282 | */ | ||
1283 | if (atomic_add_return(1, &shpchp_num_controllers) == 1) { | ||
1284 | shpchp_wq = create_singlethread_workqueue("shpchpd"); | ||
1285 | if (!shpchp_wq) | ||
1286 | return -ENOMEM; | ||
1287 | } | ||
1288 | |||
1289 | /* | ||
1290 | * Unmask all event interrupts of all slots | ||
1291 | */ | ||
1400 | for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { | 1292 | for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { |
1401 | slot_reg = readl(php_ctlr->creg + SLOT1 + 4*hp_slot ); | 1293 | slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); |
1402 | dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, | 1294 | dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, |
1403 | hp_slot, slot_reg); | 1295 | hp_slot, slot_reg); |
1404 | tempdword = 0xe01f3fff; | 1296 | slot_reg &= ~(PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK | |
1405 | writel(tempdword, php_ctlr->creg + SLOT1 + (4*hp_slot)); | 1297 | BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK | |
1298 | CON_PFAULT_INTR_MASK | SLOT_REG_RSVDZ_MASK); | ||
1299 | shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg); | ||
1406 | } | 1300 | } |
1407 | if (!shpchp_poll_mode) { | 1301 | if (!shpchp_poll_mode) { |
1408 | /* Unmask all general input interrupts and SERR */ | 1302 | /* Unmask all general input interrupts and SERR */ |
1409 | tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE); | 1303 | tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); |
1410 | tempdword = 0x0000000a; | 1304 | tempdword &= ~(GLOBAL_INTR_MASK | COMMAND_INTR_MASK | |
1411 | writel(tempdword, php_ctlr->creg + SERR_INTR_ENABLE); | 1305 | SERR_INTR_RSVDZ_MASK); |
1412 | tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE); | 1306 | shpc_writel(ctrl, SERR_INTR_ENABLE, tempdword); |
1307 | tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); | ||
1413 | dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); | 1308 | dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); |
1414 | } | 1309 | } |
1415 | 1310 | ||
diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c index 257adc233996..0a6b25ef194c 100644 --- a/drivers/pci/hotplug/shpchp_pci.c +++ b/drivers/pci/hotplug/shpchp_pci.c | |||
@@ -47,21 +47,28 @@ static void program_fw_provided_values(struct pci_dev *dev) | |||
47 | return; | 47 | return; |
48 | 48 | ||
49 | /* use default values if we can't get them from firmware */ | 49 | /* use default values if we can't get them from firmware */ |
50 | if (get_hp_params_from_firmware(dev, &hpp)) { | 50 | if (get_hp_params_from_firmware(dev, &hpp) || |
51 | hpp.cache_line_size = 8; | 51 | !hpp.t0 || (hpp.t0->revision > 1)) { |
52 | hpp.latency_timer = 0x40; | 52 | printk(KERN_WARNING |
53 | hpp.enable_serr = 0; | 53 | "%s: Could not get hotplug parameters. Use defaults\n", |
54 | hpp.enable_perr = 0; | 54 | __FUNCTION__); |
55 | hpp.t0 = &hpp.type0_data; | ||
56 | hpp.t0->revision = 0; | ||
57 | hpp.t0->cache_line_size = 8; | ||
58 | hpp.t0->latency_timer = 0x40; | ||
59 | hpp.t0->enable_serr = 0; | ||
60 | hpp.t0->enable_perr = 0; | ||
55 | } | 61 | } |
56 | 62 | ||
57 | pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, hpp.cache_line_size); | 63 | pci_write_config_byte(dev, |
58 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, hpp.latency_timer); | 64 | PCI_CACHE_LINE_SIZE, hpp.t0->cache_line_size); |
65 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, hpp.t0->latency_timer); | ||
59 | pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); | 66 | pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); |
60 | if (hpp.enable_serr) | 67 | if (hpp.t0->enable_serr) |
61 | pci_cmd |= PCI_COMMAND_SERR; | 68 | pci_cmd |= PCI_COMMAND_SERR; |
62 | else | 69 | else |
63 | pci_cmd &= ~PCI_COMMAND_SERR; | 70 | pci_cmd &= ~PCI_COMMAND_SERR; |
64 | if (hpp.enable_perr) | 71 | if (hpp.t0->enable_perr) |
65 | pci_cmd |= PCI_COMMAND_PARITY; | 72 | pci_cmd |= PCI_COMMAND_PARITY; |
66 | else | 73 | else |
67 | pci_cmd &= ~PCI_COMMAND_PARITY; | 74 | pci_cmd &= ~PCI_COMMAND_PARITY; |
@@ -70,13 +77,13 @@ static void program_fw_provided_values(struct pci_dev *dev) | |||
70 | /* Program bridge control value and child devices */ | 77 | /* Program bridge control value and child devices */ |
71 | if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { | 78 | if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { |
72 | pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, | 79 | pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, |
73 | hpp.latency_timer); | 80 | hpp.t0->latency_timer); |
74 | pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); | 81 | pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); |
75 | if (hpp.enable_serr) | 82 | if (hpp.t0->enable_serr) |
76 | pci_bctl |= PCI_BRIDGE_CTL_SERR; | 83 | pci_bctl |= PCI_BRIDGE_CTL_SERR; |
77 | else | 84 | else |
78 | pci_bctl &= ~PCI_BRIDGE_CTL_SERR; | 85 | pci_bctl &= ~PCI_BRIDGE_CTL_SERR; |
79 | if (hpp.enable_perr) | 86 | if (hpp.t0->enable_perr) |
80 | pci_bctl |= PCI_BRIDGE_CTL_PARITY; | 87 | pci_bctl |= PCI_BRIDGE_CTL_PARITY; |
81 | else | 88 | else |
82 | pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; | 89 | pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; |
diff --git a/drivers/pci/msi-altix.c b/drivers/pci/msi-altix.c new file mode 100644 index 000000000000..bed4183a5e39 --- /dev/null +++ b/drivers/pci/msi-altix.c | |||
@@ -0,0 +1,210 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2006 Silicon Graphics, Inc. All Rights Reserved. | ||
7 | */ | ||
8 | |||
9 | #include <linux/types.h> | ||
10 | #include <linux/pci.h> | ||
11 | #include <linux/cpumask.h> | ||
12 | |||
13 | #include <asm/sn/addrs.h> | ||
14 | #include <asm/sn/intr.h> | ||
15 | #include <asm/sn/pcibus_provider_defs.h> | ||
16 | #include <asm/sn/pcidev.h> | ||
17 | #include <asm/sn/nodepda.h> | ||
18 | |||
19 | #include "msi.h" | ||
20 | |||
21 | struct sn_msi_info { | ||
22 | u64 pci_addr; | ||
23 | struct sn_irq_info *sn_irq_info; | ||
24 | }; | ||
25 | |||
26 | static struct sn_msi_info *sn_msi_info; | ||
27 | |||
28 | static void | ||
29 | sn_msi_teardown(unsigned int vector) | ||
30 | { | ||
31 | nasid_t nasid; | ||
32 | int widget; | ||
33 | struct pci_dev *pdev; | ||
34 | struct pcidev_info *sn_pdev; | ||
35 | struct sn_irq_info *sn_irq_info; | ||
36 | struct pcibus_bussoft *bussoft; | ||
37 | struct sn_pcibus_provider *provider; | ||
38 | |||
39 | sn_irq_info = sn_msi_info[vector].sn_irq_info; | ||
40 | if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0) | ||
41 | return; | ||
42 | |||
43 | sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; | ||
44 | pdev = sn_pdev->pdi_linux_pcidev; | ||
45 | provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
46 | |||
47 | (*provider->dma_unmap)(pdev, | ||
48 | sn_msi_info[vector].pci_addr, | ||
49 | PCI_DMA_FROMDEVICE); | ||
50 | sn_msi_info[vector].pci_addr = 0; | ||
51 | |||
52 | bussoft = SN_PCIDEV_BUSSOFT(pdev); | ||
53 | nasid = NASID_GET(bussoft->bs_base); | ||
54 | widget = (nasid & 1) ? | ||
55 | TIO_SWIN_WIDGETNUM(bussoft->bs_base) : | ||
56 | SWIN_WIDGETNUM(bussoft->bs_base); | ||
57 | |||
58 | sn_intr_free(nasid, widget, sn_irq_info); | ||
59 | sn_msi_info[vector].sn_irq_info = NULL; | ||
60 | |||
61 | return; | ||
62 | } | ||
63 | |||
64 | int | ||
65 | sn_msi_setup(struct pci_dev *pdev, unsigned int vector, | ||
66 | u32 *addr_hi, u32 *addr_lo, u32 *data) | ||
67 | { | ||
68 | int widget; | ||
69 | int status; | ||
70 | nasid_t nasid; | ||
71 | u64 bus_addr; | ||
72 | struct sn_irq_info *sn_irq_info; | ||
73 | struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev); | ||
74 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
75 | |||
76 | if (bussoft == NULL) | ||
77 | return -EINVAL; | ||
78 | |||
79 | if (provider == NULL || provider->dma_map_consistent == NULL) | ||
80 | return -EINVAL; | ||
81 | |||
82 | /* | ||
83 | * Set up the vector plumbing. Let the prom (via sn_intr_alloc) | ||
84 | * decide which cpu to direct this msi at by default. | ||
85 | */ | ||
86 | |||
87 | nasid = NASID_GET(bussoft->bs_base); | ||
88 | widget = (nasid & 1) ? | ||
89 | TIO_SWIN_WIDGETNUM(bussoft->bs_base) : | ||
90 | SWIN_WIDGETNUM(bussoft->bs_base); | ||
91 | |||
92 | sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL); | ||
93 | if (! sn_irq_info) | ||
94 | return -ENOMEM; | ||
95 | |||
96 | status = sn_intr_alloc(nasid, widget, sn_irq_info, vector, -1, -1); | ||
97 | if (status) { | ||
98 | kfree(sn_irq_info); | ||
99 | return -ENOMEM; | ||
100 | } | ||
101 | |||
102 | sn_irq_info->irq_int_bit = -1; /* mark this as an MSI irq */ | ||
103 | sn_irq_fixup(pdev, sn_irq_info); | ||
104 | |||
105 | /* Prom probably should fill these in, but doesn't ... */ | ||
106 | sn_irq_info->irq_bridge_type = bussoft->bs_asic_type; | ||
107 | sn_irq_info->irq_bridge = (void *)bussoft->bs_base; | ||
108 | |||
109 | /* | ||
110 | * Map the xio address into bus space | ||
111 | */ | ||
112 | bus_addr = (*provider->dma_map_consistent)(pdev, | ||
113 | sn_irq_info->irq_xtalkaddr, | ||
114 | sizeof(sn_irq_info->irq_xtalkaddr), | ||
115 | SN_DMA_MSI|SN_DMA_ADDR_XIO); | ||
116 | if (! bus_addr) { | ||
117 | sn_intr_free(nasid, widget, sn_irq_info); | ||
118 | kfree(sn_irq_info); | ||
119 | return -ENOMEM; | ||
120 | } | ||
121 | |||
122 | sn_msi_info[vector].sn_irq_info = sn_irq_info; | ||
123 | sn_msi_info[vector].pci_addr = bus_addr; | ||
124 | |||
125 | *addr_hi = (u32)(bus_addr >> 32); | ||
126 | *addr_lo = (u32)(bus_addr & 0x00000000ffffffff); | ||
127 | |||
128 | /* | ||
129 | * In the SN platform, bit 16 is a "send vector" bit which | ||
130 | * must be present in order to move the vector through the system. | ||
131 | */ | ||
132 | *data = 0x100 + (unsigned int)vector; | ||
133 | |||
134 | #ifdef CONFIG_SMP | ||
135 | set_irq_affinity_info((vector & 0xff), sn_irq_info->irq_cpuid, 0); | ||
136 | #endif | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | static void | ||
142 | sn_msi_target(unsigned int vector, unsigned int cpu, | ||
143 | u32 *addr_hi, u32 *addr_lo) | ||
144 | { | ||
145 | int slice; | ||
146 | nasid_t nasid; | ||
147 | u64 bus_addr; | ||
148 | struct pci_dev *pdev; | ||
149 | struct pcidev_info *sn_pdev; | ||
150 | struct sn_irq_info *sn_irq_info; | ||
151 | struct sn_irq_info *new_irq_info; | ||
152 | struct sn_pcibus_provider *provider; | ||
153 | |||
154 | sn_irq_info = sn_msi_info[vector].sn_irq_info; | ||
155 | if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0) | ||
156 | return; | ||
157 | |||
158 | /* | ||
159 | * Release XIO resources for the old MSI PCI address | ||
160 | */ | ||
161 | |||
162 | sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; | ||
163 | pdev = sn_pdev->pdi_linux_pcidev; | ||
164 | provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
165 | |||
166 | bus_addr = (u64)(*addr_hi) << 32 | (u64)(*addr_lo); | ||
167 | (*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE); | ||
168 | sn_msi_info[vector].pci_addr = 0; | ||
169 | |||
170 | nasid = cpuid_to_nasid(cpu); | ||
171 | slice = cpuid_to_slice(cpu); | ||
172 | |||
173 | new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice); | ||
174 | sn_msi_info[vector].sn_irq_info = new_irq_info; | ||
175 | if (new_irq_info == NULL) | ||
176 | return; | ||
177 | |||
178 | /* | ||
179 | * Map the xio address into bus space | ||
180 | */ | ||
181 | |||
182 | bus_addr = (*provider->dma_map_consistent)(pdev, | ||
183 | new_irq_info->irq_xtalkaddr, | ||
184 | sizeof(new_irq_info->irq_xtalkaddr), | ||
185 | SN_DMA_MSI|SN_DMA_ADDR_XIO); | ||
186 | |||
187 | sn_msi_info[vector].pci_addr = bus_addr; | ||
188 | *addr_hi = (u32)(bus_addr >> 32); | ||
189 | *addr_lo = (u32)(bus_addr & 0x00000000ffffffff); | ||
190 | } | ||
191 | |||
192 | struct msi_ops sn_msi_ops = { | ||
193 | .setup = sn_msi_setup, | ||
194 | .teardown = sn_msi_teardown, | ||
195 | #ifdef CONFIG_SMP | ||
196 | .target = sn_msi_target, | ||
197 | #endif | ||
198 | }; | ||
199 | |||
200 | int | ||
201 | sn_msi_init(void) | ||
202 | { | ||
203 | sn_msi_info = | ||
204 | kzalloc(sizeof(struct sn_msi_info) * NR_VECTORS, GFP_KERNEL); | ||
205 | if (! sn_msi_info) | ||
206 | return -ENOMEM; | ||
207 | |||
208 | msi_register(&sn_msi_ops); | ||
209 | return 0; | ||
210 | } | ||
diff --git a/drivers/pci/msi-apic.c b/drivers/pci/msi-apic.c new file mode 100644 index 000000000000..0eb5fe9003a2 --- /dev/null +++ b/drivers/pci/msi-apic.c | |||
@@ -0,0 +1,100 @@ | |||
1 | /* | ||
2 | * MSI hooks for standard x86 apic | ||
3 | */ | ||
4 | |||
5 | #include <linux/pci.h> | ||
6 | #include <linux/irq.h> | ||
7 | |||
8 | #include "msi.h" | ||
9 | |||
10 | /* | ||
11 | * Shifts for APIC-based data | ||
12 | */ | ||
13 | |||
14 | #define MSI_DATA_VECTOR_SHIFT 0 | ||
15 | #define MSI_DATA_VECTOR(v) (((u8)v) << MSI_DATA_VECTOR_SHIFT) | ||
16 | |||
17 | #define MSI_DATA_DELIVERY_SHIFT 8 | ||
18 | #define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_SHIFT) | ||
19 | #define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_SHIFT) | ||
20 | |||
21 | #define MSI_DATA_LEVEL_SHIFT 14 | ||
22 | #define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT) | ||
23 | #define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT) | ||
24 | |||
25 | #define MSI_DATA_TRIGGER_SHIFT 15 | ||
26 | #define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT) | ||
27 | #define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT) | ||
28 | |||
29 | /* | ||
30 | * Shift/mask fields for APIC-based bus address | ||
31 | */ | ||
32 | |||
33 | #define MSI_ADDR_HEADER 0xfee00000 | ||
34 | |||
35 | #define MSI_ADDR_DESTID_MASK 0xfff0000f | ||
36 | #define MSI_ADDR_DESTID_CPU(cpu) ((cpu) << MSI_TARGET_CPU_SHIFT) | ||
37 | |||
38 | #define MSI_ADDR_DESTMODE_SHIFT 2 | ||
39 | #define MSI_ADDR_DESTMODE_PHYS (0 << MSI_ADDR_DESTMODE_SHIFT) | ||
40 | #define MSI_ADDR_DESTMODE_LOGIC (1 << MSI_ADDR_DESTMODE_SHIFT) | ||
41 | |||
42 | #define MSI_ADDR_REDIRECTION_SHIFT 3 | ||
43 | #define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) | ||
44 | #define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT) | ||
45 | |||
46 | |||
47 | static void | ||
48 | msi_target_apic(unsigned int vector, | ||
49 | unsigned int dest_cpu, | ||
50 | u32 *address_hi, /* in/out */ | ||
51 | u32 *address_lo) /* in/out */ | ||
52 | { | ||
53 | u32 addr = *address_lo; | ||
54 | |||
55 | addr &= MSI_ADDR_DESTID_MASK; | ||
56 | addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu)); | ||
57 | |||
58 | *address_lo = addr; | ||
59 | } | ||
60 | |||
61 | static int | ||
62 | msi_setup_apic(struct pci_dev *pdev, /* unused in generic */ | ||
63 | unsigned int vector, | ||
64 | u32 *address_hi, | ||
65 | u32 *address_lo, | ||
66 | u32 *data) | ||
67 | { | ||
68 | unsigned long dest_phys_id; | ||
69 | |||
70 | dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map)); | ||
71 | |||
72 | *address_hi = 0; | ||
73 | *address_lo = MSI_ADDR_HEADER | | ||
74 | MSI_ADDR_DESTMODE_PHYS | | ||
75 | MSI_ADDR_REDIRECTION_CPU | | ||
76 | MSI_ADDR_DESTID_CPU(dest_phys_id); | ||
77 | |||
78 | *data = MSI_DATA_TRIGGER_EDGE | | ||
79 | MSI_DATA_LEVEL_ASSERT | | ||
80 | MSI_DATA_DELIVERY_FIXED | | ||
81 | MSI_DATA_VECTOR(vector); | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static void | ||
87 | msi_teardown_apic(unsigned int vector) | ||
88 | { | ||
89 | return; /* no-op */ | ||
90 | } | ||
91 | |||
92 | /* | ||
93 | * Generic ops used on most IA archs/platforms. Set with msi_register() | ||
94 | */ | ||
95 | |||
96 | struct msi_ops msi_apic_ops = { | ||
97 | .setup = msi_setup_apic, | ||
98 | .teardown = msi_teardown_apic, | ||
99 | .target = msi_target_apic, | ||
100 | }; | ||
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 9855c4c920b8..7f8429284fab 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -23,8 +23,6 @@ | |||
23 | #include "pci.h" | 23 | #include "pci.h" |
24 | #include "msi.h" | 24 | #include "msi.h" |
25 | 25 | ||
26 | #define MSI_TARGET_CPU first_cpu(cpu_online_map) | ||
27 | |||
28 | static DEFINE_SPINLOCK(msi_lock); | 26 | static DEFINE_SPINLOCK(msi_lock); |
29 | static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL }; | 27 | static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL }; |
30 | static kmem_cache_t* msi_cachep; | 28 | static kmem_cache_t* msi_cachep; |
@@ -37,9 +35,17 @@ static int nr_msix_devices; | |||
37 | 35 | ||
38 | #ifndef CONFIG_X86_IO_APIC | 36 | #ifndef CONFIG_X86_IO_APIC |
39 | int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; | 37 | int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; |
40 | u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 }; | ||
41 | #endif | 38 | #endif |
42 | 39 | ||
40 | static struct msi_ops *msi_ops; | ||
41 | |||
42 | int | ||
43 | msi_register(struct msi_ops *ops) | ||
44 | { | ||
45 | msi_ops = ops; | ||
46 | return 0; | ||
47 | } | ||
48 | |||
43 | static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags) | 49 | static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags) |
44 | { | 50 | { |
45 | memset(p, 0, NR_IRQS * sizeof(struct msi_desc)); | 51 | memset(p, 0, NR_IRQS * sizeof(struct msi_desc)); |
@@ -92,7 +98,7 @@ static void msi_set_mask_bit(unsigned int vector, int flag) | |||
92 | static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) | 98 | static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) |
93 | { | 99 | { |
94 | struct msi_desc *entry; | 100 | struct msi_desc *entry; |
95 | struct msg_address address; | 101 | u32 address_hi, address_lo; |
96 | unsigned int irq = vector; | 102 | unsigned int irq = vector; |
97 | unsigned int dest_cpu = first_cpu(cpu_mask); | 103 | unsigned int dest_cpu = first_cpu(cpu_mask); |
98 | 104 | ||
@@ -108,28 +114,36 @@ static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) | |||
108 | if (!pos) | 114 | if (!pos) |
109 | return; | 115 | return; |
110 | 116 | ||
117 | pci_read_config_dword(entry->dev, msi_upper_address_reg(pos), | ||
118 | &address_hi); | ||
111 | pci_read_config_dword(entry->dev, msi_lower_address_reg(pos), | 119 | pci_read_config_dword(entry->dev, msi_lower_address_reg(pos), |
112 | &address.lo_address.value); | 120 | &address_lo); |
113 | address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK; | 121 | |
114 | address.lo_address.value |= (cpu_physical_id(dest_cpu) << | 122 | msi_ops->target(vector, dest_cpu, &address_hi, &address_lo); |
115 | MSI_TARGET_CPU_SHIFT); | 123 | |
116 | entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu); | 124 | pci_write_config_dword(entry->dev, msi_upper_address_reg(pos), |
125 | address_hi); | ||
117 | pci_write_config_dword(entry->dev, msi_lower_address_reg(pos), | 126 | pci_write_config_dword(entry->dev, msi_lower_address_reg(pos), |
118 | address.lo_address.value); | 127 | address_lo); |
119 | set_native_irq_info(irq, cpu_mask); | 128 | set_native_irq_info(irq, cpu_mask); |
120 | break; | 129 | break; |
121 | } | 130 | } |
122 | case PCI_CAP_ID_MSIX: | 131 | case PCI_CAP_ID_MSIX: |
123 | { | 132 | { |
124 | int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + | 133 | int offset_hi = |
125 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET; | 134 | entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + |
126 | 135 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET; | |
127 | address.lo_address.value = readl(entry->mask_base + offset); | 136 | int offset_lo = |
128 | address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK; | 137 | entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + |
129 | address.lo_address.value |= (cpu_physical_id(dest_cpu) << | 138 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET; |
130 | MSI_TARGET_CPU_SHIFT); | 139 | |
131 | entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu); | 140 | address_hi = readl(entry->mask_base + offset_hi); |
132 | writel(address.lo_address.value, entry->mask_base + offset); | 141 | address_lo = readl(entry->mask_base + offset_lo); |
142 | |||
143 | msi_ops->target(vector, dest_cpu, &address_hi, &address_lo); | ||
144 | |||
145 | writel(address_hi, entry->mask_base + offset_hi); | ||
146 | writel(address_lo, entry->mask_base + offset_lo); | ||
133 | set_native_irq_info(irq, cpu_mask); | 147 | set_native_irq_info(irq, cpu_mask); |
134 | break; | 148 | break; |
135 | } | 149 | } |
@@ -251,30 +265,6 @@ static struct hw_interrupt_type msi_irq_wo_maskbit_type = { | |||
251 | .set_affinity = set_msi_affinity | 265 | .set_affinity = set_msi_affinity |
252 | }; | 266 | }; |
253 | 267 | ||
254 | static void msi_data_init(struct msg_data *msi_data, | ||
255 | unsigned int vector) | ||
256 | { | ||
257 | memset(msi_data, 0, sizeof(struct msg_data)); | ||
258 | msi_data->vector = (u8)vector; | ||
259 | msi_data->delivery_mode = MSI_DELIVERY_MODE; | ||
260 | msi_data->level = MSI_LEVEL_MODE; | ||
261 | msi_data->trigger = MSI_TRIGGER_MODE; | ||
262 | } | ||
263 | |||
264 | static void msi_address_init(struct msg_address *msi_address) | ||
265 | { | ||
266 | unsigned int dest_id; | ||
267 | unsigned long dest_phys_id = cpu_physical_id(MSI_TARGET_CPU); | ||
268 | |||
269 | memset(msi_address, 0, sizeof(struct msg_address)); | ||
270 | msi_address->hi_address = (u32)0; | ||
271 | dest_id = (MSI_ADDRESS_HEADER << MSI_ADDRESS_HEADER_SHIFT); | ||
272 | msi_address->lo_address.u.dest_mode = MSI_PHYSICAL_MODE; | ||
273 | msi_address->lo_address.u.redirection_hint = MSI_REDIRECTION_HINT_MODE; | ||
274 | msi_address->lo_address.u.dest_id = dest_id; | ||
275 | msi_address->lo_address.value |= (dest_phys_id << MSI_TARGET_CPU_SHIFT); | ||
276 | } | ||
277 | |||
278 | static int msi_free_vector(struct pci_dev* dev, int vector, int reassign); | 268 | static int msi_free_vector(struct pci_dev* dev, int vector, int reassign); |
279 | static int assign_msi_vector(void) | 269 | static int assign_msi_vector(void) |
280 | { | 270 | { |
@@ -369,13 +359,29 @@ static int msi_init(void) | |||
369 | return status; | 359 | return status; |
370 | } | 360 | } |
371 | 361 | ||
362 | status = msi_arch_init(); | ||
363 | if (status < 0) { | ||
364 | pci_msi_enable = 0; | ||
365 | printk(KERN_WARNING | ||
366 | "PCI: MSI arch init failed. MSI disabled.\n"); | ||
367 | return status; | ||
368 | } | ||
369 | |||
370 | if (! msi_ops) { | ||
371 | printk(KERN_WARNING | ||
372 | "PCI: MSI ops not registered. MSI disabled.\n"); | ||
373 | status = -EINVAL; | ||
374 | return status; | ||
375 | } | ||
376 | |||
377 | last_alloc_vector = assign_irq_vector(AUTO_ASSIGN); | ||
372 | status = msi_cache_init(); | 378 | status = msi_cache_init(); |
373 | if (status < 0) { | 379 | if (status < 0) { |
374 | pci_msi_enable = 0; | 380 | pci_msi_enable = 0; |
375 | printk(KERN_WARNING "PCI: MSI cache init failed\n"); | 381 | printk(KERN_WARNING "PCI: MSI cache init failed\n"); |
376 | return status; | 382 | return status; |
377 | } | 383 | } |
378 | last_alloc_vector = assign_irq_vector(AUTO_ASSIGN); | 384 | |
379 | if (last_alloc_vector < 0) { | 385 | if (last_alloc_vector < 0) { |
380 | pci_msi_enable = 0; | 386 | pci_msi_enable = 0; |
381 | printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n"); | 387 | printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n"); |
@@ -442,9 +448,11 @@ static void enable_msi_mode(struct pci_dev *dev, int pos, int type) | |||
442 | /* Set enabled bits to single MSI & enable MSI_enable bit */ | 448 | /* Set enabled bits to single MSI & enable MSI_enable bit */ |
443 | msi_enable(control, 1); | 449 | msi_enable(control, 1); |
444 | pci_write_config_word(dev, msi_control_reg(pos), control); | 450 | pci_write_config_word(dev, msi_control_reg(pos), control); |
451 | dev->msi_enabled = 1; | ||
445 | } else { | 452 | } else { |
446 | msix_enable(control); | 453 | msix_enable(control); |
447 | pci_write_config_word(dev, msi_control_reg(pos), control); | 454 | pci_write_config_word(dev, msi_control_reg(pos), control); |
455 | dev->msix_enabled = 1; | ||
448 | } | 456 | } |
449 | if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { | 457 | if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { |
450 | /* PCI Express Endpoint device detected */ | 458 | /* PCI Express Endpoint device detected */ |
@@ -461,9 +469,11 @@ void disable_msi_mode(struct pci_dev *dev, int pos, int type) | |||
461 | /* Set enabled bits to single MSI & enable MSI_enable bit */ | 469 | /* Set enabled bits to single MSI & enable MSI_enable bit */ |
462 | msi_disable(control); | 470 | msi_disable(control); |
463 | pci_write_config_word(dev, msi_control_reg(pos), control); | 471 | pci_write_config_word(dev, msi_control_reg(pos), control); |
472 | dev->msi_enabled = 0; | ||
464 | } else { | 473 | } else { |
465 | msix_disable(control); | 474 | msix_disable(control); |
466 | pci_write_config_word(dev, msi_control_reg(pos), control); | 475 | pci_write_config_word(dev, msi_control_reg(pos), control); |
476 | dev->msix_enabled = 0; | ||
467 | } | 477 | } |
468 | if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { | 478 | if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { |
469 | /* PCI Express Endpoint device detected */ | 479 | /* PCI Express Endpoint device detected */ |
@@ -538,7 +548,6 @@ int pci_save_msi_state(struct pci_dev *dev) | |||
538 | pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, &cap[i++]); | 548 | pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, &cap[i++]); |
539 | if (control & PCI_MSI_FLAGS_MASKBIT) | 549 | if (control & PCI_MSI_FLAGS_MASKBIT) |
540 | pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, &cap[i++]); | 550 | pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, &cap[i++]); |
541 | disable_msi_mode(dev, pos, PCI_CAP_ID_MSI); | ||
542 | save_state->cap_nr = PCI_CAP_ID_MSI; | 551 | save_state->cap_nr = PCI_CAP_ID_MSI; |
543 | pci_add_saved_cap(dev, save_state); | 552 | pci_add_saved_cap(dev, save_state); |
544 | return 0; | 553 | return 0; |
@@ -575,6 +584,8 @@ void pci_restore_msi_state(struct pci_dev *dev) | |||
575 | int pci_save_msix_state(struct pci_dev *dev) | 584 | int pci_save_msix_state(struct pci_dev *dev) |
576 | { | 585 | { |
577 | int pos; | 586 | int pos; |
587 | int temp; | ||
588 | int vector, head, tail = 0; | ||
578 | u16 control; | 589 | u16 control; |
579 | struct pci_cap_saved_state *save_state; | 590 | struct pci_cap_saved_state *save_state; |
580 | 591 | ||
@@ -582,6 +593,7 @@ int pci_save_msix_state(struct pci_dev *dev) | |||
582 | if (pos <= 0 || dev->no_msi) | 593 | if (pos <= 0 || dev->no_msi) |
583 | return 0; | 594 | return 0; |
584 | 595 | ||
596 | /* save the capability */ | ||
585 | pci_read_config_word(dev, msi_control_reg(pos), &control); | 597 | pci_read_config_word(dev, msi_control_reg(pos), &control); |
586 | if (!(control & PCI_MSIX_FLAGS_ENABLE)) | 598 | if (!(control & PCI_MSIX_FLAGS_ENABLE)) |
587 | return 0; | 599 | return 0; |
@@ -593,7 +605,38 @@ int pci_save_msix_state(struct pci_dev *dev) | |||
593 | } | 605 | } |
594 | *((u16 *)&save_state->data[0]) = control; | 606 | *((u16 *)&save_state->data[0]) = control; |
595 | 607 | ||
596 | disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); | 608 | /* save the table */ |
609 | temp = dev->irq; | ||
610 | if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) { | ||
611 | kfree(save_state); | ||
612 | return -EINVAL; | ||
613 | } | ||
614 | |||
615 | vector = head = dev->irq; | ||
616 | while (head != tail) { | ||
617 | int j; | ||
618 | void __iomem *base; | ||
619 | struct msi_desc *entry; | ||
620 | |||
621 | entry = msi_desc[vector]; | ||
622 | base = entry->mask_base; | ||
623 | j = entry->msi_attrib.entry_nr; | ||
624 | |||
625 | entry->address_lo_save = | ||
626 | readl(base + j * PCI_MSIX_ENTRY_SIZE + | ||
627 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | ||
628 | entry->address_hi_save = | ||
629 | readl(base + j * PCI_MSIX_ENTRY_SIZE + | ||
630 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | ||
631 | entry->data_save = | ||
632 | readl(base + j * PCI_MSIX_ENTRY_SIZE + | ||
633 | PCI_MSIX_ENTRY_DATA_OFFSET); | ||
634 | |||
635 | tail = msi_desc[vector]->link.tail; | ||
636 | vector = tail; | ||
637 | } | ||
638 | dev->irq = temp; | ||
639 | |||
597 | save_state->cap_nr = PCI_CAP_ID_MSIX; | 640 | save_state->cap_nr = PCI_CAP_ID_MSIX; |
598 | pci_add_saved_cap(dev, save_state); | 641 | pci_add_saved_cap(dev, save_state); |
599 | return 0; | 642 | return 0; |
@@ -606,8 +649,6 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
606 | int vector, head, tail = 0; | 649 | int vector, head, tail = 0; |
607 | void __iomem *base; | 650 | void __iomem *base; |
608 | int j; | 651 | int j; |
609 | struct msg_address address; | ||
610 | struct msg_data data; | ||
611 | struct msi_desc *entry; | 652 | struct msi_desc *entry; |
612 | int temp; | 653 | int temp; |
613 | struct pci_cap_saved_state *save_state; | 654 | struct pci_cap_saved_state *save_state; |
@@ -633,20 +674,13 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
633 | base = entry->mask_base; | 674 | base = entry->mask_base; |
634 | j = entry->msi_attrib.entry_nr; | 675 | j = entry->msi_attrib.entry_nr; |
635 | 676 | ||
636 | msi_address_init(&address); | 677 | writel(entry->address_lo_save, |
637 | msi_data_init(&data, vector); | ||
638 | |||
639 | address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK; | ||
640 | address.lo_address.value |= entry->msi_attrib.current_cpu << | ||
641 | MSI_TARGET_CPU_SHIFT; | ||
642 | |||
643 | writel(address.lo_address.value, | ||
644 | base + j * PCI_MSIX_ENTRY_SIZE + | 678 | base + j * PCI_MSIX_ENTRY_SIZE + |
645 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | 679 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); |
646 | writel(address.hi_address, | 680 | writel(entry->address_hi_save, |
647 | base + j * PCI_MSIX_ENTRY_SIZE + | 681 | base + j * PCI_MSIX_ENTRY_SIZE + |
648 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | 682 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); |
649 | writel(*(u32*)&data, | 683 | writel(entry->data_save, |
650 | base + j * PCI_MSIX_ENTRY_SIZE + | 684 | base + j * PCI_MSIX_ENTRY_SIZE + |
651 | PCI_MSIX_ENTRY_DATA_OFFSET); | 685 | PCI_MSIX_ENTRY_DATA_OFFSET); |
652 | 686 | ||
@@ -660,30 +694,32 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
660 | } | 694 | } |
661 | #endif | 695 | #endif |
662 | 696 | ||
663 | static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) | 697 | static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry) |
664 | { | 698 | { |
665 | struct msg_address address; | 699 | int status; |
666 | struct msg_data data; | 700 | u32 address_hi; |
701 | u32 address_lo; | ||
702 | u32 data; | ||
667 | int pos, vector = dev->irq; | 703 | int pos, vector = dev->irq; |
668 | u16 control; | 704 | u16 control; |
669 | 705 | ||
670 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); | 706 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); |
671 | pci_read_config_word(dev, msi_control_reg(pos), &control); | 707 | pci_read_config_word(dev, msi_control_reg(pos), &control); |
708 | |||
672 | /* Configure MSI capability structure */ | 709 | /* Configure MSI capability structure */ |
673 | msi_address_init(&address); | 710 | status = msi_ops->setup(dev, vector, &address_hi, &address_lo, &data); |
674 | msi_data_init(&data, vector); | 711 | if (status < 0) |
675 | entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >> | 712 | return status; |
676 | MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK); | 713 | |
677 | pci_write_config_dword(dev, msi_lower_address_reg(pos), | 714 | pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo); |
678 | address.lo_address.value); | ||
679 | if (is_64bit_address(control)) { | 715 | if (is_64bit_address(control)) { |
680 | pci_write_config_dword(dev, | 716 | pci_write_config_dword(dev, |
681 | msi_upper_address_reg(pos), address.hi_address); | 717 | msi_upper_address_reg(pos), address_hi); |
682 | pci_write_config_word(dev, | 718 | pci_write_config_word(dev, |
683 | msi_data_reg(pos, 1), *((u32*)&data)); | 719 | msi_data_reg(pos, 1), data); |
684 | } else | 720 | } else |
685 | pci_write_config_word(dev, | 721 | pci_write_config_word(dev, |
686 | msi_data_reg(pos, 0), *((u32*)&data)); | 722 | msi_data_reg(pos, 0), data); |
687 | if (entry->msi_attrib.maskbit) { | 723 | if (entry->msi_attrib.maskbit) { |
688 | unsigned int maskbits, temp; | 724 | unsigned int maskbits, temp; |
689 | /* All MSIs are unmasked by default, Mask them all */ | 725 | /* All MSIs are unmasked by default, Mask them all */ |
@@ -697,6 +733,8 @@ static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) | |||
697 | msi_mask_bits_reg(pos, is_64bit_address(control)), | 733 | msi_mask_bits_reg(pos, is_64bit_address(control)), |
698 | maskbits); | 734 | maskbits); |
699 | } | 735 | } |
736 | |||
737 | return 0; | ||
700 | } | 738 | } |
701 | 739 | ||
702 | /** | 740 | /** |
@@ -710,6 +748,7 @@ static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) | |||
710 | **/ | 748 | **/ |
711 | static int msi_capability_init(struct pci_dev *dev) | 749 | static int msi_capability_init(struct pci_dev *dev) |
712 | { | 750 | { |
751 | int status; | ||
713 | struct msi_desc *entry; | 752 | struct msi_desc *entry; |
714 | int pos, vector; | 753 | int pos, vector; |
715 | u16 control; | 754 | u16 control; |
@@ -742,7 +781,12 @@ static int msi_capability_init(struct pci_dev *dev) | |||
742 | /* Replace with MSI handler */ | 781 | /* Replace with MSI handler */ |
743 | irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit); | 782 | irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit); |
744 | /* Configure MSI capability structure */ | 783 | /* Configure MSI capability structure */ |
745 | msi_register_init(dev, entry); | 784 | status = msi_register_init(dev, entry); |
785 | if (status != 0) { | ||
786 | dev->irq = entry->msi_attrib.default_vector; | ||
787 | kmem_cache_free(msi_cachep, entry); | ||
788 | return status; | ||
789 | } | ||
746 | 790 | ||
747 | attach_msi_entry(entry, vector); | 791 | attach_msi_entry(entry, vector); |
748 | /* Set MSI enabled bits */ | 792 | /* Set MSI enabled bits */ |
@@ -765,8 +809,10 @@ static int msix_capability_init(struct pci_dev *dev, | |||
765 | struct msix_entry *entries, int nvec) | 809 | struct msix_entry *entries, int nvec) |
766 | { | 810 | { |
767 | struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; | 811 | struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; |
768 | struct msg_address address; | 812 | u32 address_hi; |
769 | struct msg_data data; | 813 | u32 address_lo; |
814 | u32 data; | ||
815 | int status; | ||
770 | int vector, pos, i, j, nr_entries, temp = 0; | 816 | int vector, pos, i, j, nr_entries, temp = 0; |
771 | unsigned long phys_addr; | 817 | unsigned long phys_addr; |
772 | u32 table_offset; | 818 | u32 table_offset; |
@@ -822,18 +868,20 @@ static int msix_capability_init(struct pci_dev *dev, | |||
822 | /* Replace with MSI-X handler */ | 868 | /* Replace with MSI-X handler */ |
823 | irq_handler_init(PCI_CAP_ID_MSIX, vector, 1); | 869 | irq_handler_init(PCI_CAP_ID_MSIX, vector, 1); |
824 | /* Configure MSI-X capability structure */ | 870 | /* Configure MSI-X capability structure */ |
825 | msi_address_init(&address); | 871 | status = msi_ops->setup(dev, vector, |
826 | msi_data_init(&data, vector); | 872 | &address_hi, |
827 | entry->msi_attrib.current_cpu = | 873 | &address_lo, |
828 | ((address.lo_address.u.dest_id >> | 874 | &data); |
829 | MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK); | 875 | if (status < 0) |
830 | writel(address.lo_address.value, | 876 | break; |
877 | |||
878 | writel(address_lo, | ||
831 | base + j * PCI_MSIX_ENTRY_SIZE + | 879 | base + j * PCI_MSIX_ENTRY_SIZE + |
832 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | 880 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); |
833 | writel(address.hi_address, | 881 | writel(address_hi, |
834 | base + j * PCI_MSIX_ENTRY_SIZE + | 882 | base + j * PCI_MSIX_ENTRY_SIZE + |
835 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | 883 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); |
836 | writel(*(u32*)&data, | 884 | writel(data, |
837 | base + j * PCI_MSIX_ENTRY_SIZE + | 885 | base + j * PCI_MSIX_ENTRY_SIZE + |
838 | PCI_MSIX_ENTRY_DATA_OFFSET); | 886 | PCI_MSIX_ENTRY_DATA_OFFSET); |
839 | attach_msi_entry(entry, vector); | 887 | attach_msi_entry(entry, vector); |
@@ -865,6 +913,7 @@ static int msix_capability_init(struct pci_dev *dev, | |||
865 | **/ | 913 | **/ |
866 | int pci_enable_msi(struct pci_dev* dev) | 914 | int pci_enable_msi(struct pci_dev* dev) |
867 | { | 915 | { |
916 | struct pci_bus *bus; | ||
868 | int pos, temp, status = -EINVAL; | 917 | int pos, temp, status = -EINVAL; |
869 | u16 control; | 918 | u16 control; |
870 | 919 | ||
@@ -874,8 +923,9 @@ int pci_enable_msi(struct pci_dev* dev) | |||
874 | if (dev->no_msi) | 923 | if (dev->no_msi) |
875 | return status; | 924 | return status; |
876 | 925 | ||
877 | if (dev->bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) | 926 | for (bus = dev->bus; bus; bus = bus->parent) |
878 | return -EINVAL; | 927 | if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) |
928 | return -EINVAL; | ||
879 | 929 | ||
880 | temp = dev->irq; | 930 | temp = dev->irq; |
881 | 931 | ||
@@ -887,23 +937,23 @@ int pci_enable_msi(struct pci_dev* dev) | |||
887 | if (!pos) | 937 | if (!pos) |
888 | return -EINVAL; | 938 | return -EINVAL; |
889 | 939 | ||
890 | pci_read_config_word(dev, msi_control_reg(pos), &control); | ||
891 | if (control & PCI_MSI_FLAGS_ENABLE) | ||
892 | return 0; /* Already in MSI mode */ | ||
893 | |||
894 | if (!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) { | 940 | if (!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) { |
895 | /* Lookup Sucess */ | 941 | /* Lookup Sucess */ |
896 | unsigned long flags; | 942 | unsigned long flags; |
897 | 943 | ||
944 | pci_read_config_word(dev, msi_control_reg(pos), &control); | ||
945 | if (control & PCI_MSI_FLAGS_ENABLE) | ||
946 | return 0; /* Already in MSI mode */ | ||
898 | spin_lock_irqsave(&msi_lock, flags); | 947 | spin_lock_irqsave(&msi_lock, flags); |
899 | if (!vector_irq[dev->irq]) { | 948 | if (!vector_irq[dev->irq]) { |
900 | msi_desc[dev->irq]->msi_attrib.state = 0; | 949 | msi_desc[dev->irq]->msi_attrib.state = 0; |
901 | vector_irq[dev->irq] = -1; | 950 | vector_irq[dev->irq] = -1; |
902 | nr_released_vectors--; | 951 | nr_released_vectors--; |
903 | spin_unlock_irqrestore(&msi_lock, flags); | 952 | spin_unlock_irqrestore(&msi_lock, flags); |
904 | msi_register_init(dev, msi_desc[dev->irq]); | 953 | status = msi_register_init(dev, msi_desc[dev->irq]); |
905 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); | 954 | if (status == 0) |
906 | return 0; | 955 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); |
956 | return status; | ||
907 | } | 957 | } |
908 | spin_unlock_irqrestore(&msi_lock, flags); | 958 | spin_unlock_irqrestore(&msi_lock, flags); |
909 | dev->irq = temp; | 959 | dev->irq = temp; |
@@ -980,6 +1030,8 @@ static int msi_free_vector(struct pci_dev* dev, int vector, int reassign) | |||
980 | void __iomem *base; | 1030 | void __iomem *base; |
981 | unsigned long flags; | 1031 | unsigned long flags; |
982 | 1032 | ||
1033 | msi_ops->teardown(vector); | ||
1034 | |||
983 | spin_lock_irqsave(&msi_lock, flags); | 1035 | spin_lock_irqsave(&msi_lock, flags); |
984 | entry = msi_desc[vector]; | 1036 | entry = msi_desc[vector]; |
985 | if (!entry || entry->dev != dev) { | 1037 | if (!entry || entry->dev != dev) { |
@@ -1008,33 +1060,8 @@ static int msi_free_vector(struct pci_dev* dev, int vector, int reassign) | |||
1008 | entry_nr * PCI_MSIX_ENTRY_SIZE + | 1060 | entry_nr * PCI_MSIX_ENTRY_SIZE + |
1009 | PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); | 1061 | PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); |
1010 | 1062 | ||
1011 | if (head == vector) { | 1063 | if (head == vector) |
1012 | /* | ||
1013 | * Detect last MSI-X vector to be released. | ||
1014 | * Release the MSI-X memory-mapped table. | ||
1015 | */ | ||
1016 | #if 0 | ||
1017 | int pos, nr_entries; | ||
1018 | unsigned long phys_addr; | ||
1019 | u32 table_offset; | ||
1020 | u16 control; | ||
1021 | u8 bir; | ||
1022 | |||
1023 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); | ||
1024 | pci_read_config_word(dev, msi_control_reg(pos), | ||
1025 | &control); | ||
1026 | nr_entries = multi_msix_capable(control); | ||
1027 | pci_read_config_dword(dev, msix_table_offset_reg(pos), | ||
1028 | &table_offset); | ||
1029 | bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK); | ||
1030 | table_offset &= ~PCI_MSIX_FLAGS_BIRMASK; | ||
1031 | phys_addr = pci_resource_start(dev, bir) + table_offset; | ||
1032 | /* | ||
1033 | * FIXME! and what did you want to do with phys_addr? | ||
1034 | */ | ||
1035 | #endif | ||
1036 | iounmap(base); | 1064 | iounmap(base); |
1037 | } | ||
1038 | } | 1065 | } |
1039 | 1066 | ||
1040 | return 0; | 1067 | return 0; |
@@ -1108,6 +1135,7 @@ static int reroute_msix_table(int head, struct msix_entry *entries, int *nvec) | |||
1108 | **/ | 1135 | **/ |
1109 | int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) | 1136 | int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) |
1110 | { | 1137 | { |
1138 | struct pci_bus *bus; | ||
1111 | int status, pos, nr_entries, free_vectors; | 1139 | int status, pos, nr_entries, free_vectors; |
1112 | int i, j, temp; | 1140 | int i, j, temp; |
1113 | u16 control; | 1141 | u16 control; |
@@ -1116,6 +1144,13 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) | |||
1116 | if (!pci_msi_enable || !dev || !entries) | 1144 | if (!pci_msi_enable || !dev || !entries) |
1117 | return -EINVAL; | 1145 | return -EINVAL; |
1118 | 1146 | ||
1147 | if (dev->no_msi) | ||
1148 | return -EINVAL; | ||
1149 | |||
1150 | for (bus = dev->bus; bus; bus = bus->parent) | ||
1151 | if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) | ||
1152 | return -EINVAL; | ||
1153 | |||
1119 | status = msi_init(); | 1154 | status = msi_init(); |
1120 | if (status < 0) | 1155 | if (status < 0) |
1121 | return status; | 1156 | return status; |
@@ -1300,24 +1335,6 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev) | |||
1300 | } | 1335 | } |
1301 | msi_free_vector(dev, vector, 0); | 1336 | msi_free_vector(dev, vector, 0); |
1302 | if (warning) { | 1337 | if (warning) { |
1303 | /* Force to release the MSI-X memory-mapped table */ | ||
1304 | #if 0 | ||
1305 | unsigned long phys_addr; | ||
1306 | u32 table_offset; | ||
1307 | u16 control; | ||
1308 | u8 bir; | ||
1309 | |||
1310 | pci_read_config_word(dev, msi_control_reg(pos), | ||
1311 | &control); | ||
1312 | pci_read_config_dword(dev, msix_table_offset_reg(pos), | ||
1313 | &table_offset); | ||
1314 | bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK); | ||
1315 | table_offset &= ~PCI_MSIX_FLAGS_BIRMASK; | ||
1316 | phys_addr = pci_resource_start(dev, bir) + table_offset; | ||
1317 | /* | ||
1318 | * FIXME! and what did you want to do with phys_addr? | ||
1319 | */ | ||
1320 | #endif | ||
1321 | iounmap(base); | 1338 | iounmap(base); |
1322 | printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " | 1339 | printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " |
1323 | "called without free_irq() on all MSI-X vectors\n", | 1340 | "called without free_irq() on all MSI-X vectors\n", |
diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index 4ac52d441e47..56951c39d3a3 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h | |||
@@ -6,6 +6,68 @@ | |||
6 | #ifndef MSI_H | 6 | #ifndef MSI_H |
7 | #define MSI_H | 7 | #define MSI_H |
8 | 8 | ||
9 | /* | ||
10 | * MSI operation vector. Used by the msi core code (drivers/pci/msi.c) | ||
11 | * to abstract platform-specific tasks relating to MSI address generation | ||
12 | * and resource management. | ||
13 | */ | ||
14 | struct msi_ops { | ||
15 | /** | ||
16 | * setup - generate an MSI bus address and data for a given vector | ||
17 | * @pdev: PCI device context (in) | ||
18 | * @vector: vector allocated by the msi core (in) | ||
19 | * @addr_hi: upper 32 bits of PCI bus MSI address (out) | ||
20 | * @addr_lo: lower 32 bits of PCI bus MSI address (out) | ||
21 | * @data: MSI data payload (out) | ||
22 | * | ||
23 | * Description: The setup op is used to generate a PCI bus addres and | ||
24 | * data which the msi core will program into the card MSI capability | ||
25 | * registers. The setup routine is responsible for picking an initial | ||
26 | * cpu to target the MSI at. The setup routine is responsible for | ||
27 | * examining pdev to determine the MSI capabilities of the card and | ||
28 | * generating a suitable address/data. The setup routine is | ||
29 | * responsible for allocating and tracking any system resources it | ||
30 | * needs to route the MSI to the cpu it picks, and for associating | ||
31 | * those resources with the passed in vector. | ||
32 | * | ||
33 | * Returns 0 if the MSI address/data was successfully setup. | ||
34 | **/ | ||
35 | |||
36 | int (*setup) (struct pci_dev *pdev, unsigned int vector, | ||
37 | u32 *addr_hi, u32 *addr_lo, u32 *data); | ||
38 | |||
39 | /** | ||
40 | * teardown - release resources allocated by setup | ||
41 | * @vector: vector context for resources (in) | ||
42 | * | ||
43 | * Description: The teardown op is used to release any resources | ||
44 | * that were allocated in the setup routine associated with the passed | ||
45 | * in vector. | ||
46 | **/ | ||
47 | |||
48 | void (*teardown) (unsigned int vector); | ||
49 | |||
50 | /** | ||
51 | * target - retarget an MSI at a different cpu | ||
52 | * @vector: vector context for resources (in) | ||
53 | * @cpu: new cpu to direct vector at (in) | ||
54 | * @addr_hi: new value of PCI bus upper 32 bits (in/out) | ||
55 | * @addr_lo: new value of PCI bus lower 32 bits (in/out) | ||
56 | * | ||
57 | * Description: The target op is used to redirect an MSI vector | ||
58 | * at a different cpu. addr_hi/addr_lo coming in are the existing | ||
59 | * values that the MSI core has programmed into the card. The | ||
60 | * target code is responsible for freeing any resources (if any) | ||
61 | * associated with the old address, and generating a new PCI bus | ||
62 | * addr_hi/addr_lo that will redirect the vector at the indicated cpu. | ||
63 | **/ | ||
64 | |||
65 | void (*target) (unsigned int vector, unsigned int cpu, | ||
66 | u32 *addr_hi, u32 *addr_lo); | ||
67 | }; | ||
68 | |||
69 | extern int msi_register(struct msi_ops *ops); | ||
70 | |||
9 | #include <asm/msi.h> | 71 | #include <asm/msi.h> |
10 | 72 | ||
11 | /* | 73 | /* |
@@ -63,67 +125,6 @@ extern int pci_vector_resources(int last, int nr_released); | |||
63 | #define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK) | 125 | #define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK) |
64 | #define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK) | 126 | #define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK) |
65 | 127 | ||
66 | /* | ||
67 | * MSI Defined Data Structures | ||
68 | */ | ||
69 | #define MSI_ADDRESS_HEADER 0xfee | ||
70 | #define MSI_ADDRESS_HEADER_SHIFT 12 | ||
71 | #define MSI_ADDRESS_HEADER_MASK 0xfff000 | ||
72 | #define MSI_ADDRESS_DEST_ID_MASK 0xfff0000f | ||
73 | #define MSI_TARGET_CPU_MASK 0xff | ||
74 | #define MSI_DELIVERY_MODE 0 | ||
75 | #define MSI_LEVEL_MODE 1 /* Edge always assert */ | ||
76 | #define MSI_TRIGGER_MODE 0 /* MSI is edge sensitive */ | ||
77 | #define MSI_PHYSICAL_MODE 0 | ||
78 | #define MSI_LOGICAL_MODE 1 | ||
79 | #define MSI_REDIRECTION_HINT_MODE 0 | ||
80 | |||
81 | struct msg_data { | ||
82 | #if defined(__LITTLE_ENDIAN_BITFIELD) | ||
83 | __u32 vector : 8; | ||
84 | __u32 delivery_mode : 3; /* 000b: FIXED | 001b: lowest prior */ | ||
85 | __u32 reserved_1 : 3; | ||
86 | __u32 level : 1; /* 0: deassert | 1: assert */ | ||
87 | __u32 trigger : 1; /* 0: edge | 1: level */ | ||
88 | __u32 reserved_2 : 16; | ||
89 | #elif defined(__BIG_ENDIAN_BITFIELD) | ||
90 | __u32 reserved_2 : 16; | ||
91 | __u32 trigger : 1; /* 0: edge | 1: level */ | ||
92 | __u32 level : 1; /* 0: deassert | 1: assert */ | ||
93 | __u32 reserved_1 : 3; | ||
94 | __u32 delivery_mode : 3; /* 000b: FIXED | 001b: lowest prior */ | ||
95 | __u32 vector : 8; | ||
96 | #else | ||
97 | #error "Bitfield endianness not defined! Check your byteorder.h" | ||
98 | #endif | ||
99 | } __attribute__ ((packed)); | ||
100 | |||
101 | struct msg_address { | ||
102 | union { | ||
103 | struct { | ||
104 | #if defined(__LITTLE_ENDIAN_BITFIELD) | ||
105 | __u32 reserved_1 : 2; | ||
106 | __u32 dest_mode : 1; /*0:physic | 1:logic */ | ||
107 | __u32 redirection_hint: 1; /*0: dedicated CPU | ||
108 | 1: lowest priority */ | ||
109 | __u32 reserved_2 : 4; | ||
110 | __u32 dest_id : 24; /* Destination ID */ | ||
111 | #elif defined(__BIG_ENDIAN_BITFIELD) | ||
112 | __u32 dest_id : 24; /* Destination ID */ | ||
113 | __u32 reserved_2 : 4; | ||
114 | __u32 redirection_hint: 1; /*0: dedicated CPU | ||
115 | 1: lowest priority */ | ||
116 | __u32 dest_mode : 1; /*0:physic | 1:logic */ | ||
117 | __u32 reserved_1 : 2; | ||
118 | #else | ||
119 | #error "Bitfield endianness not defined! Check your byteorder.h" | ||
120 | #endif | ||
121 | }u; | ||
122 | __u32 value; | ||
123 | }lo_address; | ||
124 | __u32 hi_address; | ||
125 | } __attribute__ ((packed)); | ||
126 | |||
127 | struct msi_desc { | 128 | struct msi_desc { |
128 | struct { | 129 | struct { |
129 | __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */ | 130 | __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */ |
@@ -132,7 +133,7 @@ struct msi_desc { | |||
132 | __u8 reserved: 1; /* reserved */ | 133 | __u8 reserved: 1; /* reserved */ |
133 | __u8 entry_nr; /* specific enabled entry */ | 134 | __u8 entry_nr; /* specific enabled entry */ |
134 | __u8 default_vector; /* default pre-assigned vector */ | 135 | __u8 default_vector; /* default pre-assigned vector */ |
135 | __u8 current_cpu; /* current destination cpu */ | 136 | __u8 unused; /* formerly unused destination cpu*/ |
136 | }msi_attrib; | 137 | }msi_attrib; |
137 | 138 | ||
138 | struct { | 139 | struct { |
@@ -142,6 +143,14 @@ struct msi_desc { | |||
142 | 143 | ||
143 | void __iomem *mask_base; | 144 | void __iomem *mask_base; |
144 | struct pci_dev *dev; | 145 | struct pci_dev *dev; |
146 | |||
147 | #ifdef CONFIG_PM | ||
148 | /* PM save area for MSIX address/data */ | ||
149 | |||
150 | u32 address_hi_save; | ||
151 | u32 address_lo_save; | ||
152 | u32 data_save; | ||
153 | #endif | ||
145 | }; | 154 | }; |
146 | 155 | ||
147 | #endif /* MSI_H */ | 156 | #endif /* MSI_H */ |
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index c2ecae5ff0c1..bb7456c1dbac 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c | |||
@@ -267,7 +267,7 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) | |||
267 | 267 | ||
268 | 268 | ||
269 | /* ACPI bus type */ | 269 | /* ACPI bus type */ |
270 | static int pci_acpi_find_device(struct device *dev, acpi_handle *handle) | 270 | static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) |
271 | { | 271 | { |
272 | struct pci_dev * pci_dev; | 272 | struct pci_dev * pci_dev; |
273 | acpi_integer addr; | 273 | acpi_integer addr; |
@@ -281,7 +281,7 @@ static int pci_acpi_find_device(struct device *dev, acpi_handle *handle) | |||
281 | return 0; | 281 | return 0; |
282 | } | 282 | } |
283 | 283 | ||
284 | static int pci_acpi_find_root_bridge(struct device *dev, acpi_handle *handle) | 284 | static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle) |
285 | { | 285 | { |
286 | int num; | 286 | int num; |
287 | unsigned int seg, bus; | 287 | unsigned int seg, bus; |
@@ -299,21 +299,21 @@ static int pci_acpi_find_root_bridge(struct device *dev, acpi_handle *handle) | |||
299 | return 0; | 299 | return 0; |
300 | } | 300 | } |
301 | 301 | ||
302 | static struct acpi_bus_type pci_acpi_bus = { | 302 | static struct acpi_bus_type acpi_pci_bus = { |
303 | .bus = &pci_bus_type, | 303 | .bus = &pci_bus_type, |
304 | .find_device = pci_acpi_find_device, | 304 | .find_device = acpi_pci_find_device, |
305 | .find_bridge = pci_acpi_find_root_bridge, | 305 | .find_bridge = acpi_pci_find_root_bridge, |
306 | }; | 306 | }; |
307 | 307 | ||
308 | static int __init pci_acpi_init(void) | 308 | static int __init acpi_pci_init(void) |
309 | { | 309 | { |
310 | int ret; | 310 | int ret; |
311 | 311 | ||
312 | ret = register_acpi_bus_type(&pci_acpi_bus); | 312 | ret = register_acpi_bus_type(&acpi_pci_bus); |
313 | if (ret) | 313 | if (ret) |
314 | return 0; | 314 | return 0; |
315 | platform_pci_choose_state = acpi_pci_choose_state; | 315 | platform_pci_choose_state = acpi_pci_choose_state; |
316 | platform_pci_set_power_state = acpi_pci_set_power_state; | 316 | platform_pci_set_power_state = acpi_pci_set_power_state; |
317 | return 0; | 317 | return 0; |
318 | } | 318 | } |
319 | arch_initcall(pci_acpi_init); | 319 | arch_initcall(acpi_pci_init); |
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 56ac2bc003c7..bc405c035ce3 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
@@ -43,6 +43,29 @@ pci_config_attr(subsystem_vendor, "0x%04x\n"); | |||
43 | pci_config_attr(subsystem_device, "0x%04x\n"); | 43 | pci_config_attr(subsystem_device, "0x%04x\n"); |
44 | pci_config_attr(class, "0x%06x\n"); | 44 | pci_config_attr(class, "0x%06x\n"); |
45 | pci_config_attr(irq, "%u\n"); | 45 | pci_config_attr(irq, "%u\n"); |
46 | pci_config_attr(is_enabled, "%u\n"); | ||
47 | |||
48 | static ssize_t broken_parity_status_show(struct device *dev, | ||
49 | struct device_attribute *attr, | ||
50 | char *buf) | ||
51 | { | ||
52 | struct pci_dev *pdev = to_pci_dev(dev); | ||
53 | return sprintf (buf, "%u\n", pdev->broken_parity_status); | ||
54 | } | ||
55 | |||
56 | static ssize_t broken_parity_status_store(struct device *dev, | ||
57 | struct device_attribute *attr, | ||
58 | const char *buf, size_t count) | ||
59 | { | ||
60 | struct pci_dev *pdev = to_pci_dev(dev); | ||
61 | ssize_t consumed = -EINVAL; | ||
62 | |||
63 | if ((count > 0) && (*buf == '0' || *buf == '1')) { | ||
64 | pdev->broken_parity_status = *buf == '1' ? 1 : 0; | ||
65 | consumed = count; | ||
66 | } | ||
67 | return consumed; | ||
68 | } | ||
46 | 69 | ||
47 | static ssize_t local_cpus_show(struct device *dev, | 70 | static ssize_t local_cpus_show(struct device *dev, |
48 | struct device_attribute *attr, char *buf) | 71 | struct device_attribute *attr, char *buf) |
@@ -90,6 +113,25 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, | |||
90 | (u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8), | 113 | (u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8), |
91 | (u8)(pci_dev->class)); | 114 | (u8)(pci_dev->class)); |
92 | } | 115 | } |
116 | static ssize_t | ||
117 | is_enabled_store(struct device *dev, struct device_attribute *attr, | ||
118 | const char *buf, size_t count) | ||
119 | { | ||
120 | struct pci_dev *pdev = to_pci_dev(dev); | ||
121 | |||
122 | /* this can crash the machine when done on the "wrong" device */ | ||
123 | if (!capable(CAP_SYS_ADMIN)) | ||
124 | return count; | ||
125 | |||
126 | if (*buf == '0') | ||
127 | pci_disable_device(pdev); | ||
128 | |||
129 | if (*buf == '1') | ||
130 | pci_enable_device(pdev); | ||
131 | |||
132 | return count; | ||
133 | } | ||
134 | |||
93 | 135 | ||
94 | struct device_attribute pci_dev_attrs[] = { | 136 | struct device_attribute pci_dev_attrs[] = { |
95 | __ATTR_RO(resource), | 137 | __ATTR_RO(resource), |
@@ -101,6 +143,9 @@ struct device_attribute pci_dev_attrs[] = { | |||
101 | __ATTR_RO(irq), | 143 | __ATTR_RO(irq), |
102 | __ATTR_RO(local_cpus), | 144 | __ATTR_RO(local_cpus), |
103 | __ATTR_RO(modalias), | 145 | __ATTR_RO(modalias), |
146 | __ATTR(enable, 0600, is_enabled_show, is_enabled_store), | ||
147 | __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR), | ||
148 | broken_parity_status_show,broken_parity_status_store), | ||
104 | __ATTR_NULL, | 149 | __ATTR_NULL, |
105 | }; | 150 | }; |
106 | 151 | ||
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index fde41cc14734..d408a3c30426 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -517,7 +517,12 @@ pci_enable_device_bars(struct pci_dev *dev, int bars) | |||
517 | int | 517 | int |
518 | pci_enable_device(struct pci_dev *dev) | 518 | pci_enable_device(struct pci_dev *dev) |
519 | { | 519 | { |
520 | int err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); | 520 | int err; |
521 | |||
522 | if (dev->is_enabled) | ||
523 | return 0; | ||
524 | |||
525 | err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); | ||
521 | if (err) | 526 | if (err) |
522 | return err; | 527 | return err; |
523 | pci_fixup_device(pci_fixup_enable, dev); | 528 | pci_fixup_device(pci_fixup_enable, dev); |
@@ -546,7 +551,14 @@ void | |||
546 | pci_disable_device(struct pci_dev *dev) | 551 | pci_disable_device(struct pci_dev *dev) |
547 | { | 552 | { |
548 | u16 pci_command; | 553 | u16 pci_command; |
549 | 554 | ||
555 | if (dev->msi_enabled) | ||
556 | disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), | ||
557 | PCI_CAP_ID_MSI); | ||
558 | if (dev->msix_enabled) | ||
559 | disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), | ||
560 | PCI_CAP_ID_MSIX); | ||
561 | |||
550 | pci_read_config_word(dev, PCI_COMMAND, &pci_command); | 562 | pci_read_config_word(dev, PCI_COMMAND, &pci_command); |
551 | if (pci_command & PCI_COMMAND_MASTER) { | 563 | if (pci_command & PCI_COMMAND_MASTER) { |
552 | pci_command &= ~PCI_COMMAND_MASTER; | 564 | pci_command &= ~PCI_COMMAND_MASTER; |
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 30630cbe2fe3..29bdeca031a8 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h | |||
@@ -40,7 +40,7 @@ extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int | |||
40 | extern void pci_remove_legacy_files(struct pci_bus *bus); | 40 | extern void pci_remove_legacy_files(struct pci_bus *bus); |
41 | 41 | ||
42 | /* Lock for read/write access to pci device and bus lists */ | 42 | /* Lock for read/write access to pci device and bus lists */ |
43 | extern spinlock_t pci_bus_lock; | 43 | extern struct rw_semaphore pci_bus_sem; |
44 | 44 | ||
45 | #ifdef CONFIG_X86_IO_APIC | 45 | #ifdef CONFIG_X86_IO_APIC |
46 | extern int pci_msi_quirk; | 46 | extern int pci_msi_quirk; |
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index a10ed9dab2c2..f89dbc3738b7 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -180,25 +180,31 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) | |||
180 | res->flags |= pci_calc_resource_flags(l); | 180 | res->flags |= pci_calc_resource_flags(l); |
181 | if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK)) | 181 | if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK)) |
182 | == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) { | 182 | == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) { |
183 | pci_read_config_dword(dev, reg+4, &l); | 183 | u32 szhi, lhi; |
184 | pci_read_config_dword(dev, reg+4, &lhi); | ||
185 | pci_write_config_dword(dev, reg+4, ~0); | ||
186 | pci_read_config_dword(dev, reg+4, &szhi); | ||
187 | pci_write_config_dword(dev, reg+4, lhi); | ||
188 | szhi = pci_size(lhi, szhi, 0xffffffff); | ||
184 | next++; | 189 | next++; |
185 | #if BITS_PER_LONG == 64 | 190 | #if BITS_PER_LONG == 64 |
186 | res->start |= ((unsigned long) l) << 32; | 191 | res->start |= ((unsigned long) lhi) << 32; |
187 | res->end = res->start + sz; | 192 | res->end = res->start + sz; |
188 | pci_write_config_dword(dev, reg+4, ~0); | 193 | if (szhi) { |
189 | pci_read_config_dword(dev, reg+4, &sz); | ||
190 | pci_write_config_dword(dev, reg+4, l); | ||
191 | sz = pci_size(l, sz, 0xffffffff); | ||
192 | if (sz) { | ||
193 | /* This BAR needs > 4GB? Wow. */ | 194 | /* This BAR needs > 4GB? Wow. */ |
194 | res->end |= (unsigned long)sz<<32; | 195 | res->end |= (unsigned long)szhi<<32; |
195 | } | 196 | } |
196 | #else | 197 | #else |
197 | if (l) { | 198 | if (szhi) { |
198 | printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", pci_name(dev)); | 199 | printk(KERN_ERR "PCI: Unable to handle 64-bit BAR for device %s\n", pci_name(dev)); |
199 | res->start = 0; | 200 | res->start = 0; |
200 | res->flags = 0; | 201 | res->flags = 0; |
201 | continue; | 202 | } else if (lhi) { |
203 | /* 64-bit wide address, treat as disabled */ | ||
204 | pci_write_config_dword(dev, reg, l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK); | ||
205 | pci_write_config_dword(dev, reg+4, 0); | ||
206 | res->start = 0; | ||
207 | res->end = sz; | ||
202 | } | 208 | } |
203 | #endif | 209 | #endif |
204 | } | 210 | } |
@@ -377,9 +383,9 @@ struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_de | |||
377 | 383 | ||
378 | child = pci_alloc_child_bus(parent, dev, busnr); | 384 | child = pci_alloc_child_bus(parent, dev, busnr); |
379 | if (child) { | 385 | if (child) { |
380 | spin_lock(&pci_bus_lock); | 386 | down_write(&pci_bus_sem); |
381 | list_add_tail(&child->node, &parent->children); | 387 | list_add_tail(&child->node, &parent->children); |
382 | spin_unlock(&pci_bus_lock); | 388 | up_write(&pci_bus_sem); |
383 | } | 389 | } |
384 | return child; | 390 | return child; |
385 | } | 391 | } |
@@ -838,9 +844,9 @@ void __devinit pci_device_add(struct pci_dev *dev, struct pci_bus *bus) | |||
838 | * and the bus list for fixup functions, etc. | 844 | * and the bus list for fixup functions, etc. |
839 | */ | 845 | */ |
840 | INIT_LIST_HEAD(&dev->global_list); | 846 | INIT_LIST_HEAD(&dev->global_list); |
841 | spin_lock(&pci_bus_lock); | 847 | down_write(&pci_bus_sem); |
842 | list_add_tail(&dev->bus_list, &bus->devices); | 848 | list_add_tail(&dev->bus_list, &bus->devices); |
843 | spin_unlock(&pci_bus_lock); | 849 | up_write(&pci_bus_sem); |
844 | } | 850 | } |
845 | 851 | ||
846 | struct pci_dev * __devinit | 852 | struct pci_dev * __devinit |
@@ -975,9 +981,10 @@ struct pci_bus * __devinit pci_create_bus(struct device *parent, | |||
975 | pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus); | 981 | pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus); |
976 | goto err_out; | 982 | goto err_out; |
977 | } | 983 | } |
978 | spin_lock(&pci_bus_lock); | 984 | |
985 | down_write(&pci_bus_sem); | ||
979 | list_add_tail(&b->node, &pci_root_buses); | 986 | list_add_tail(&b->node, &pci_root_buses); |
980 | spin_unlock(&pci_bus_lock); | 987 | up_write(&pci_bus_sem); |
981 | 988 | ||
982 | memset(dev, 0, sizeof(*dev)); | 989 | memset(dev, 0, sizeof(*dev)); |
983 | dev->parent = parent; | 990 | dev->parent = parent; |
@@ -1017,9 +1024,9 @@ class_dev_create_file_err: | |||
1017 | class_dev_reg_err: | 1024 | class_dev_reg_err: |
1018 | device_unregister(dev); | 1025 | device_unregister(dev); |
1019 | dev_reg_err: | 1026 | dev_reg_err: |
1020 | spin_lock(&pci_bus_lock); | 1027 | down_write(&pci_bus_sem); |
1021 | list_del(&b->node); | 1028 | list_del(&b->node); |
1022 | spin_unlock(&pci_bus_lock); | 1029 | up_write(&pci_bus_sem); |
1023 | err_out: | 1030 | err_out: |
1024 | kfree(dev); | 1031 | kfree(dev); |
1025 | kfree(b); | 1032 | kfree(b); |
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index d378478612fb..4364d793f73b 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c | |||
@@ -24,6 +24,17 @@ | |||
24 | #include <linux/acpi.h> | 24 | #include <linux/acpi.h> |
25 | #include "pci.h" | 25 | #include "pci.h" |
26 | 26 | ||
27 | /* The Mellanox Tavor device gives false positive parity errors | ||
28 | * Mark this device with a broken_parity_status, to allow | ||
29 | * PCI scanning code to "skip" this now blacklisted device. | ||
30 | */ | ||
31 | static void __devinit quirk_mellanox_tavor(struct pci_dev *dev) | ||
32 | { | ||
33 | dev->broken_parity_status = 1; /* This device gives false positives */ | ||
34 | } | ||
35 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX,PCI_DEVICE_ID_MELLANOX_TAVOR,quirk_mellanox_tavor); | ||
36 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX,PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE,quirk_mellanox_tavor); | ||
37 | |||
27 | /* Deal with broken BIOS'es that neglect to enable passive release, | 38 | /* Deal with broken BIOS'es that neglect to enable passive release, |
28 | which can cause problems in combination with the 82441FX/PPro MTRRs */ | 39 | which can cause problems in combination with the 82441FX/PPro MTRRs */ |
29 | static void __devinit quirk_passive_release(struct pci_dev *dev) | 40 | static void __devinit quirk_passive_release(struct pci_dev *dev) |
@@ -878,27 +889,30 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_e | |||
878 | * when a PCI-Soundcard is added. The BIOS only gives Options | 889 | * when a PCI-Soundcard is added. The BIOS only gives Options |
879 | * "Disabled" and "AUTO". This Quirk Sets the corresponding | 890 | * "Disabled" and "AUTO". This Quirk Sets the corresponding |
880 | * Register-Value to enable the Soundcard. | 891 | * Register-Value to enable the Soundcard. |
892 | * | ||
893 | * FIXME: Presently this quirk will run on anything that has an 8237 | ||
894 | * which isn't correct, we need to check DMI tables or something in | ||
895 | * order to make sure it only runs on the MSI-K8T-Neo2Fir. Because it | ||
896 | * runs everywhere at present we suppress the printk output in most | ||
897 | * irrelevant cases. | ||
881 | */ | 898 | */ |
882 | static void __init k8t_sound_hostbridge(struct pci_dev *dev) | 899 | static void __init k8t_sound_hostbridge(struct pci_dev *dev) |
883 | { | 900 | { |
884 | unsigned char val; | 901 | unsigned char val; |
885 | 902 | ||
886 | printk(KERN_INFO "PCI: Quirk-MSI-K8T Soundcard On\n"); | ||
887 | pci_read_config_byte(dev, 0x50, &val); | 903 | pci_read_config_byte(dev, 0x50, &val); |
888 | if (val == 0x88 || val == 0xc8) { | 904 | if (val == 0x88 || val == 0xc8) { |
905 | /* Assume it's probably a MSI-K8T-Neo2Fir */ | ||
906 | printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, attempting to turn soundcard ON\n"); | ||
889 | pci_write_config_byte(dev, 0x50, val & (~0x40)); | 907 | pci_write_config_byte(dev, 0x50, val & (~0x40)); |
890 | 908 | ||
891 | /* Verify the Change for Status output */ | 909 | /* Verify the Change for Status output */ |
892 | pci_read_config_byte(dev, 0x50, &val); | 910 | pci_read_config_byte(dev, 0x50, &val); |
893 | if (val & 0x40) | 911 | if (val & 0x40) |
894 | printk(KERN_INFO "PCI: MSI-K8T soundcard still off\n"); | 912 | printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard still off\n"); |
895 | else | 913 | else |
896 | printk(KERN_INFO "PCI: MSI-K8T soundcard on\n"); | 914 | printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard on\n"); |
897 | } else { | ||
898 | printk(KERN_INFO "PCI: Unexpected Value in PCI-Register: " | ||
899 | "no Change!\n"); | ||
900 | } | 915 | } |
901 | |||
902 | } | 916 | } |
903 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge); | 917 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge); |
904 | 918 | ||
@@ -1485,6 +1499,25 @@ static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev) | |||
1485 | } | 1499 | } |
1486 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io); | 1500 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io); |
1487 | 1501 | ||
1502 | /* Under some circumstances, AER is not linked with extended capabilities. | ||
1503 | * Force it to be linked by setting the corresponding control bit in the | ||
1504 | * config space. | ||
1505 | */ | ||
1506 | static void __devinit quirk_nvidia_ck804_pcie_aer_ext_cap(struct pci_dev *dev) | ||
1507 | { | ||
1508 | uint8_t b; | ||
1509 | if (pci_read_config_byte(dev, 0xf41, &b) == 0) { | ||
1510 | if (!(b & 0x20)) { | ||
1511 | pci_write_config_byte(dev, 0xf41, b | 0x20); | ||
1512 | printk(KERN_INFO | ||
1513 | "PCI: Linking AER extended capability on %s\n", | ||
1514 | pci_name(dev)); | ||
1515 | } | ||
1516 | } | ||
1517 | } | ||
1518 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, | ||
1519 | quirk_nvidia_ck804_pcie_aer_ext_cap); | ||
1520 | |||
1488 | EXPORT_SYMBOL(pcie_mch_quirk); | 1521 | EXPORT_SYMBOL(pcie_mch_quirk); |
1489 | #ifdef CONFIG_HOTPLUG | 1522 | #ifdef CONFIG_HOTPLUG |
1490 | EXPORT_SYMBOL(pci_fixup_device); | 1523 | EXPORT_SYMBOL(pci_fixup_device); |
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 1a6bf9de166f..99ffbd478b29 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c | |||
@@ -22,18 +22,18 @@ static void pci_destroy_dev(struct pci_dev *dev) | |||
22 | pci_proc_detach_device(dev); | 22 | pci_proc_detach_device(dev); |
23 | pci_remove_sysfs_dev_files(dev); | 23 | pci_remove_sysfs_dev_files(dev); |
24 | device_unregister(&dev->dev); | 24 | device_unregister(&dev->dev); |
25 | spin_lock(&pci_bus_lock); | 25 | down_write(&pci_bus_sem); |
26 | list_del(&dev->global_list); | 26 | list_del(&dev->global_list); |
27 | dev->global_list.next = dev->global_list.prev = NULL; | 27 | dev->global_list.next = dev->global_list.prev = NULL; |
28 | spin_unlock(&pci_bus_lock); | 28 | up_write(&pci_bus_sem); |
29 | } | 29 | } |
30 | 30 | ||
31 | /* Remove the device from the device lists, and prevent any further | 31 | /* Remove the device from the device lists, and prevent any further |
32 | * list accesses from this device */ | 32 | * list accesses from this device */ |
33 | spin_lock(&pci_bus_lock); | 33 | down_write(&pci_bus_sem); |
34 | list_del(&dev->bus_list); | 34 | list_del(&dev->bus_list); |
35 | dev->bus_list.next = dev->bus_list.prev = NULL; | 35 | dev->bus_list.next = dev->bus_list.prev = NULL; |
36 | spin_unlock(&pci_bus_lock); | 36 | up_write(&pci_bus_sem); |
37 | 37 | ||
38 | pci_free_resources(dev); | 38 | pci_free_resources(dev); |
39 | pci_dev_put(dev); | 39 | pci_dev_put(dev); |
@@ -62,9 +62,9 @@ void pci_remove_bus(struct pci_bus *pci_bus) | |||
62 | { | 62 | { |
63 | pci_proc_detach_bus(pci_bus); | 63 | pci_proc_detach_bus(pci_bus); |
64 | 64 | ||
65 | spin_lock(&pci_bus_lock); | 65 | down_write(&pci_bus_sem); |
66 | list_del(&pci_bus->node); | 66 | list_del(&pci_bus->node); |
67 | spin_unlock(&pci_bus_lock); | 67 | up_write(&pci_bus_sem); |
68 | pci_remove_legacy_files(pci_bus); | 68 | pci_remove_legacy_files(pci_bus); |
69 | class_device_remove_file(&pci_bus->class_dev, | 69 | class_device_remove_file(&pci_bus->class_dev, |
70 | &class_device_attr_cpuaffinity); | 70 | &class_device_attr_cpuaffinity); |
diff --git a/drivers/pci/search.c b/drivers/pci/search.c index ce7dd6e7be60..622b3f8ba820 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c | |||
@@ -13,7 +13,7 @@ | |||
13 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
14 | #include "pci.h" | 14 | #include "pci.h" |
15 | 15 | ||
16 | DEFINE_SPINLOCK(pci_bus_lock); | 16 | DECLARE_RWSEM(pci_bus_sem); |
17 | 17 | ||
18 | static struct pci_bus * __devinit | 18 | static struct pci_bus * __devinit |
19 | pci_do_find_bus(struct pci_bus* bus, unsigned char busnr) | 19 | pci_do_find_bus(struct pci_bus* bus, unsigned char busnr) |
@@ -72,11 +72,11 @@ pci_find_next_bus(const struct pci_bus *from) | |||
72 | struct pci_bus *b = NULL; | 72 | struct pci_bus *b = NULL; |
73 | 73 | ||
74 | WARN_ON(in_interrupt()); | 74 | WARN_ON(in_interrupt()); |
75 | spin_lock(&pci_bus_lock); | 75 | down_read(&pci_bus_sem); |
76 | n = from ? from->node.next : pci_root_buses.next; | 76 | n = from ? from->node.next : pci_root_buses.next; |
77 | if (n != &pci_root_buses) | 77 | if (n != &pci_root_buses) |
78 | b = pci_bus_b(n); | 78 | b = pci_bus_b(n); |
79 | spin_unlock(&pci_bus_lock); | 79 | up_read(&pci_bus_sem); |
80 | return b; | 80 | return b; |
81 | } | 81 | } |
82 | 82 | ||
@@ -124,7 +124,7 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn) | |||
124 | struct pci_dev *dev; | 124 | struct pci_dev *dev; |
125 | 125 | ||
126 | WARN_ON(in_interrupt()); | 126 | WARN_ON(in_interrupt()); |
127 | spin_lock(&pci_bus_lock); | 127 | down_read(&pci_bus_sem); |
128 | 128 | ||
129 | list_for_each(tmp, &bus->devices) { | 129 | list_for_each(tmp, &bus->devices) { |
130 | dev = pci_dev_b(tmp); | 130 | dev = pci_dev_b(tmp); |
@@ -135,7 +135,7 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn) | |||
135 | dev = NULL; | 135 | dev = NULL; |
136 | out: | 136 | out: |
137 | pci_dev_get(dev); | 137 | pci_dev_get(dev); |
138 | spin_unlock(&pci_bus_lock); | 138 | up_read(&pci_bus_sem); |
139 | return dev; | 139 | return dev; |
140 | } | 140 | } |
141 | 141 | ||
@@ -167,7 +167,7 @@ static struct pci_dev * pci_find_subsys(unsigned int vendor, | |||
167 | struct pci_dev *dev; | 167 | struct pci_dev *dev; |
168 | 168 | ||
169 | WARN_ON(in_interrupt()); | 169 | WARN_ON(in_interrupt()); |
170 | spin_lock(&pci_bus_lock); | 170 | down_read(&pci_bus_sem); |
171 | n = from ? from->global_list.next : pci_devices.next; | 171 | n = from ? from->global_list.next : pci_devices.next; |
172 | 172 | ||
173 | while (n && (n != &pci_devices)) { | 173 | while (n && (n != &pci_devices)) { |
@@ -181,7 +181,7 @@ static struct pci_dev * pci_find_subsys(unsigned int vendor, | |||
181 | } | 181 | } |
182 | dev = NULL; | 182 | dev = NULL; |
183 | exit: | 183 | exit: |
184 | spin_unlock(&pci_bus_lock); | 184 | up_read(&pci_bus_sem); |
185 | return dev; | 185 | return dev; |
186 | } | 186 | } |
187 | 187 | ||
@@ -232,7 +232,7 @@ pci_get_subsys(unsigned int vendor, unsigned int device, | |||
232 | struct pci_dev *dev; | 232 | struct pci_dev *dev; |
233 | 233 | ||
234 | WARN_ON(in_interrupt()); | 234 | WARN_ON(in_interrupt()); |
235 | spin_lock(&pci_bus_lock); | 235 | down_read(&pci_bus_sem); |
236 | n = from ? from->global_list.next : pci_devices.next; | 236 | n = from ? from->global_list.next : pci_devices.next; |
237 | 237 | ||
238 | while (n && (n != &pci_devices)) { | 238 | while (n && (n != &pci_devices)) { |
@@ -247,7 +247,7 @@ pci_get_subsys(unsigned int vendor, unsigned int device, | |||
247 | dev = NULL; | 247 | dev = NULL; |
248 | exit: | 248 | exit: |
249 | dev = pci_dev_get(dev); | 249 | dev = pci_dev_get(dev); |
250 | spin_unlock(&pci_bus_lock); | 250 | up_read(&pci_bus_sem); |
251 | pci_dev_put(from); | 251 | pci_dev_put(from); |
252 | return dev; | 252 | return dev; |
253 | } | 253 | } |
@@ -292,7 +292,7 @@ pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct p | |||
292 | struct pci_dev *dev; | 292 | struct pci_dev *dev; |
293 | 293 | ||
294 | WARN_ON(in_interrupt()); | 294 | WARN_ON(in_interrupt()); |
295 | spin_lock(&pci_bus_lock); | 295 | down_read(&pci_bus_sem); |
296 | n = from ? from->global_list.prev : pci_devices.prev; | 296 | n = from ? from->global_list.prev : pci_devices.prev; |
297 | 297 | ||
298 | while (n && (n != &pci_devices)) { | 298 | while (n && (n != &pci_devices)) { |
@@ -304,7 +304,7 @@ pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct p | |||
304 | } | 304 | } |
305 | dev = NULL; | 305 | dev = NULL; |
306 | exit: | 306 | exit: |
307 | spin_unlock(&pci_bus_lock); | 307 | up_read(&pci_bus_sem); |
308 | return dev; | 308 | return dev; |
309 | } | 309 | } |
310 | 310 | ||
@@ -328,7 +328,7 @@ struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from) | |||
328 | struct pci_dev *dev; | 328 | struct pci_dev *dev; |
329 | 329 | ||
330 | WARN_ON(in_interrupt()); | 330 | WARN_ON(in_interrupt()); |
331 | spin_lock(&pci_bus_lock); | 331 | down_read(&pci_bus_sem); |
332 | n = from ? from->global_list.next : pci_devices.next; | 332 | n = from ? from->global_list.next : pci_devices.next; |
333 | 333 | ||
334 | while (n && (n != &pci_devices)) { | 334 | while (n && (n != &pci_devices)) { |
@@ -340,7 +340,7 @@ struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from) | |||
340 | dev = NULL; | 340 | dev = NULL; |
341 | exit: | 341 | exit: |
342 | dev = pci_dev_get(dev); | 342 | dev = pci_dev_get(dev); |
343 | spin_unlock(&pci_bus_lock); | 343 | up_read(&pci_bus_sem); |
344 | pci_dev_put(from); | 344 | pci_dev_put(from); |
345 | return dev; | 345 | return dev; |
346 | } | 346 | } |
@@ -362,7 +362,7 @@ int pci_dev_present(const struct pci_device_id *ids) | |||
362 | int found = 0; | 362 | int found = 0; |
363 | 363 | ||
364 | WARN_ON(in_interrupt()); | 364 | WARN_ON(in_interrupt()); |
365 | spin_lock(&pci_bus_lock); | 365 | down_read(&pci_bus_sem); |
366 | while (ids->vendor || ids->subvendor || ids->class_mask) { | 366 | while (ids->vendor || ids->subvendor || ids->class_mask) { |
367 | list_for_each_entry(dev, &pci_devices, global_list) { | 367 | list_for_each_entry(dev, &pci_devices, global_list) { |
368 | if (pci_match_one_device(ids, dev)) { | 368 | if (pci_match_one_device(ids, dev)) { |
@@ -372,8 +372,8 @@ int pci_dev_present(const struct pci_device_id *ids) | |||
372 | } | 372 | } |
373 | ids++; | 373 | ids++; |
374 | } | 374 | } |
375 | exit: | 375 | exit: |
376 | spin_unlock(&pci_bus_lock); | 376 | up_read(&pci_bus_sem); |
377 | return found; | 377 | return found; |
378 | } | 378 | } |
379 | EXPORT_SYMBOL(pci_dev_present); | 379 | EXPORT_SYMBOL(pci_dev_present); |
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 28ce3a7ee434..35086e80faa9 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
@@ -55,9 +55,10 @@ pbus_assign_resources_sorted(struct pci_bus *bus) | |||
55 | list_for_each_entry(dev, &bus->devices, bus_list) { | 55 | list_for_each_entry(dev, &bus->devices, bus_list) { |
56 | u16 class = dev->class >> 8; | 56 | u16 class = dev->class >> 8; |
57 | 57 | ||
58 | /* Don't touch classless devices and host bridges. */ | 58 | /* Don't touch classless devices or host bridges or ioapics. */ |
59 | if (class == PCI_CLASS_NOT_DEFINED || | 59 | if (class == PCI_CLASS_NOT_DEFINED || |
60 | class == PCI_CLASS_BRIDGE_HOST) | 60 | class == PCI_CLASS_BRIDGE_HOST || |
61 | class == PCI_CLASS_SYSTEM_PIC) | ||
61 | continue; | 62 | continue; |
62 | 63 | ||
63 | pdev_sort_resources(dev, &head); | 64 | pdev_sort_resources(dev, &head); |
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index ea9277b7f899..577f4b55c46d 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c | |||
@@ -155,6 +155,46 @@ int pci_assign_resource(struct pci_dev *dev, int resno) | |||
155 | return ret; | 155 | return ret; |
156 | } | 156 | } |
157 | 157 | ||
158 | #ifdef CONFIG_EMBEDDED | ||
159 | int pci_assign_resource_fixed(struct pci_dev *dev, int resno) | ||
160 | { | ||
161 | struct pci_bus *bus = dev->bus; | ||
162 | struct resource *res = dev->resource + resno; | ||
163 | unsigned int type_mask; | ||
164 | int i, ret = -EBUSY; | ||
165 | |||
166 | type_mask = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH; | ||
167 | |||
168 | for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) { | ||
169 | struct resource *r = bus->resource[i]; | ||
170 | if (!r) | ||
171 | continue; | ||
172 | |||
173 | /* type_mask must match */ | ||
174 | if ((res->flags ^ r->flags) & type_mask) | ||
175 | continue; | ||
176 | |||
177 | ret = request_resource(r, res); | ||
178 | |||
179 | if (ret == 0) | ||
180 | break; | ||
181 | } | ||
182 | |||
183 | if (ret) { | ||
184 | printk(KERN_ERR "PCI: Failed to allocate %s resource " | ||
185 | "#%d:%llx@%llx for %s\n", | ||
186 | res->flags & IORESOURCE_IO ? "I/O" : "mem", | ||
187 | resno, (unsigned long long)(res->end - res->start + 1), | ||
188 | (unsigned long long)res->start, pci_name(dev)); | ||
189 | } else if (resno < PCI_BRIDGE_RESOURCES) { | ||
190 | pci_update_resource(dev, res, resno); | ||
191 | } | ||
192 | |||
193 | return ret; | ||
194 | } | ||
195 | EXPORT_SYMBOL_GPL(pci_assign_resource_fixed); | ||
196 | #endif | ||
197 | |||
158 | /* Sort resources by alignment */ | 198 | /* Sort resources by alignment */ |
159 | void __devinit | 199 | void __devinit |
160 | pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) | 200 | pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) |