diff options
Diffstat (limited to 'drivers/pci/hotplug')
-rw-r--r-- | drivers/pci/hotplug/acpi_pcihp.c | 257 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp.h | 5 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 242 | ||||
-rw-r--r-- | drivers/pci/hotplug/ibmphp_core.c | 12 | ||||
-rw-r--r-- | drivers/pci/hotplug/pci_hotplug.h | 50 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp.h | 2 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_core.c | 14 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 32 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_pci.c | 152 | ||||
-rw-r--r-- | drivers/pci/hotplug/sgi_hotplug.c | 46 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp.h | 8 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_core.c | 8 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_ctrl.c | 32 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_hpc.c | 861 | ||||
-rw-r--r-- | drivers/pci/hotplug/shpchp_pci.c | 31 |
15 files changed, 1091 insertions, 661 deletions
diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index 39af9c325f3..51cb9f817c2 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 467ac70a46f..17a93f890db 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 053ee843863..d370f999782 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 e13d5b87241..59392946c2b 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 eb0d01d4723..e929b7c1142 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 92c1f0f1e1a..ce89f581586 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 601cf9045b2..c67b7c3f1dd 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 6c14d9e46b2..d77138ecb09 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 4017fb03a0b..854aaea09e4 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 8cb9abde736..f31d83c2c63 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 5c70f43908c..7208b95c6ee 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 3be4d492ccc..a14e7de1984 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 4e6381481c5..c39901dbff2 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 66123cf4dea..45facaad39b 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 257adc23399..0a6b25ef194 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; |