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