diff options
| author | rajesh.shah@intel.com <rajesh.shah@intel.com> | 2005-10-13 15:05:36 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-10-28 18:36:59 -0400 |
| commit | dbd7a78818d125a0ebd5507d4edb4dd5900006ab (patch) | |
| tree | 682a1681aad47f70bfb760fca077f54589be92c6 | |
| parent | e3b1bd572f1cdb247bb4266a593b6894dc578d6a (diff) | |
[PATCH] shpchp: use the PCI core for hotplug resource management
This patch converts the standard hotplug controller driver to use
the PCI core for resource management. This eliminates a whole lot
of duplicated code, and integrates shpchp in the system's normal
PCI handling code.
Signed-off-by: Rajesh Shah <rajesh.shah@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
| -rw-r--r-- | drivers/pci/hotplug/shpchp.h | 57 | ||||
| -rw-r--r-- | drivers/pci/hotplug/shpchp_core.c | 36 | ||||
| -rw-r--r-- | drivers/pci/hotplug/shpchp_ctrl.c | 1624 | ||||
| -rw-r--r-- | drivers/pci/hotplug/shpchp_pci.c | 482 | ||||
| -rw-r--r-- | drivers/pci/hotplug/shpchp_sysfs.c | 121 | ||||
| -rw-r--r-- | drivers/pci/hotplug/shpchprm.h | 12 | ||||
| -rw-r--r-- | drivers/pci/hotplug/shpchprm_acpi.c | 851 | ||||
| -rw-r--r-- | drivers/pci/hotplug/shpchprm_legacy.c | 294 | ||||
| -rw-r--r-- | drivers/pci/hotplug/shpchprm_legacy.h | 113 | ||||
| -rw-r--r-- | drivers/pci/hotplug/shpchprm_nonacpi.c | 278 | ||||
| -rw-r--r-- | drivers/pci/hotplug/shpchprm_nonacpi.h | 56 |
11 files changed, 168 insertions, 3756 deletions
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index b7d1c61d6bbb..deea56c73cf2 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h | |||
| @@ -63,14 +63,7 @@ struct pci_func { | |||
| 63 | u8 switch_save; | 63 | u8 switch_save; |
| 64 | u8 presence_save; | 64 | u8 presence_save; |
| 65 | u8 pwr_save; | 65 | u8 pwr_save; |
| 66 | u32 base_length[0x06]; | ||
| 67 | u8 base_type[0x06]; | ||
| 68 | u16 reserved2; | ||
| 69 | u32 config_space[0x20]; | 66 | u32 config_space[0x20]; |
| 70 | struct pci_resource *mem_head; | ||
| 71 | struct pci_resource *p_mem_head; | ||
| 72 | struct pci_resource *io_head; | ||
| 73 | struct pci_resource *bus_head; | ||
| 74 | struct pci_dev* pci_dev; | 67 | struct pci_dev* pci_dev; |
| 75 | }; | 68 | }; |
| 76 | 69 | ||
| @@ -96,12 +89,6 @@ struct slot { | |||
| 96 | struct list_head slot_list; | 89 | struct list_head slot_list; |
| 97 | }; | 90 | }; |
| 98 | 91 | ||
| 99 | struct pci_resource { | ||
| 100 | struct pci_resource * next; | ||
| 101 | u32 base; | ||
| 102 | u32 length; | ||
| 103 | }; | ||
| 104 | |||
| 105 | struct event_info { | 92 | struct event_info { |
| 106 | u32 event_type; | 93 | u32 event_type; |
| 107 | u8 hp_slot; | 94 | u8 hp_slot; |
| @@ -113,10 +100,6 @@ struct controller { | |||
| 113 | void * hpc_ctlr_handle; /* HPC controller handle */ | 100 | void * hpc_ctlr_handle; /* HPC controller handle */ |
| 114 | int num_slots; /* Number of slots on ctlr */ | 101 | int num_slots; /* Number of slots on ctlr */ |
| 115 | int slot_num_inc; /* 1 or -1 */ | 102 | int slot_num_inc; /* 1 or -1 */ |
| 116 | struct pci_resource *mem_head; | ||
| 117 | struct pci_resource *p_mem_head; | ||
| 118 | struct pci_resource *io_head; | ||
| 119 | struct pci_resource *bus_head; | ||
| 120 | struct pci_dev *pci_dev; | 103 | struct pci_dev *pci_dev; |
| 121 | struct pci_bus *pci_bus; | 104 | struct pci_bus *pci_bus; |
| 122 | struct event_info event_queue[10]; | 105 | struct event_info event_queue[10]; |
| @@ -139,20 +122,6 @@ struct controller { | |||
| 139 | u16 vendor_id; | 122 | u16 vendor_id; |
| 140 | }; | 123 | }; |
| 141 | 124 | ||
| 142 | struct irq_mapping { | ||
| 143 | u8 barber_pole; | ||
| 144 | u8 valid_INT; | ||
| 145 | u8 interrupt[4]; | ||
| 146 | }; | ||
| 147 | |||
| 148 | struct resource_lists { | ||
| 149 | struct pci_resource *mem_head; | ||
| 150 | struct pci_resource *p_mem_head; | ||
| 151 | struct pci_resource *io_head; | ||
| 152 | struct pci_resource *bus_head; | ||
| 153 | struct irq_mapping *irqs; | ||
| 154 | }; | ||
| 155 | |||
| 156 | /* Define AMD SHPC ID */ | 125 | /* Define AMD SHPC ID */ |
| 157 | #define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450 | 126 | #define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450 |
| 158 | 127 | ||
| @@ -197,7 +166,6 @@ struct resource_lists { | |||
| 197 | #define msg_HPC_rev_error "Unsupported revision of the PCI hot plug controller found.\n" | 166 | #define msg_HPC_rev_error "Unsupported revision of the PCI hot plug controller found.\n" |
| 198 | #define msg_HPC_non_shpc "The PCI hot plug controller is not supported by this driver.\n" | 167 | #define msg_HPC_non_shpc "The PCI hot plug controller is not supported by this driver.\n" |
| 199 | #define msg_HPC_not_supported "This system is not supported by this version of shpcphd mdoule. Upgrade to a newer version of shpchpd\n" | 168 | #define msg_HPC_not_supported "This system is not supported by this version of shpcphd mdoule. Upgrade to a newer version of shpchpd\n" |
| 200 | #define msg_unable_to_save "Unable to store PCI hot plug add resource information. This system must be rebooted before adding any PCI devices.\n" | ||
| 201 | #define msg_button_on "PCI slot #%d - powering on due to button press.\n" | 169 | #define msg_button_on "PCI slot #%d - powering on due to button press.\n" |
| 202 | #define msg_button_off "PCI slot #%d - powering off due to button press.\n" | 170 | #define msg_button_off "PCI slot #%d - powering off due to button press.\n" |
| 203 | #define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n" | 171 | #define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n" |
| @@ -207,7 +175,6 @@ struct resource_lists { | |||
| 207 | extern void shpchp_create_ctrl_files (struct controller *ctrl); | 175 | extern void shpchp_create_ctrl_files (struct controller *ctrl); |
| 208 | 176 | ||
| 209 | /* controller functions */ | 177 | /* controller functions */ |
| 210 | extern int shpchprm_find_available_resources(struct controller *ctrl); | ||
| 211 | extern int shpchp_event_start_thread(void); | 178 | extern int shpchp_event_start_thread(void); |
| 212 | extern void shpchp_event_stop_thread(void); | 179 | extern void shpchp_event_stop_thread(void); |
| 213 | extern struct pci_func *shpchp_slot_create(unsigned char busnumber); | 180 | extern struct pci_func *shpchp_slot_create(unsigned char busnumber); |
| @@ -220,19 +187,10 @@ extern u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id); | |||
| 220 | extern u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id); | 187 | extern u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id); |
| 221 | extern u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id); | 188 | extern u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id); |
| 222 | 189 | ||
| 223 | /* resource functions */ | ||
| 224 | extern int shpchp_resource_sort_and_combine(struct pci_resource **head); | ||
| 225 | |||
| 226 | /* pci functions */ | 190 | /* pci functions */ |
| 227 | extern int shpchp_set_irq(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num); | ||
| 228 | /*extern int shpchp_get_bus_dev(struct controller *ctrl, u8 *bus_num, u8 *dev_num, struct slot *slot);*/ | ||
| 229 | extern int shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num); | 191 | extern int shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num); |
| 230 | extern int shpchp_save_used_resources(struct controller *ctrl, struct pci_func * func, int flag); | ||
| 231 | extern int shpchp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot); | 192 | extern int shpchp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot); |
| 232 | extern void shpchp_destroy_board_resources(struct pci_func * func); | 193 | extern int shpchp_configure_device(struct slot *p_slot); |
| 233 | extern int shpchp_return_board_resources(struct pci_func * func, struct resource_lists * resources); | ||
| 234 | extern void shpchp_destroy_resource_list(struct resource_lists * resources); | ||
| 235 | extern int shpchp_configure_device(struct controller* ctrl, struct pci_func* func); | ||
| 236 | extern int shpchp_unconfigure_device(struct pci_func* func); | 194 | extern int shpchp_unconfigure_device(struct pci_func* func); |
| 237 | 195 | ||
| 238 | 196 | ||
| @@ -240,10 +198,6 @@ extern int shpchp_unconfigure_device(struct pci_func* func); | |||
| 240 | extern struct controller *shpchp_ctrl_list; | 198 | extern struct controller *shpchp_ctrl_list; |
| 241 | extern struct pci_func *shpchp_slot_list[256]; | 199 | extern struct pci_func *shpchp_slot_list[256]; |
| 242 | 200 | ||
| 243 | /* These are added to support AMD shpc */ | ||
| 244 | extern u8 shpchp_nic_irq; | ||
| 245 | extern u8 shpchp_disk_irq; | ||
| 246 | |||
| 247 | struct ctrl_reg { | 201 | struct ctrl_reg { |
| 248 | volatile u32 base_offset; | 202 | volatile u32 base_offset; |
| 249 | volatile u32 slot_avail1; | 203 | volatile u32 slot_avail1; |
| @@ -398,15 +352,6 @@ static inline int wait_for_ctrl_irq (struct controller *ctrl) | |||
| 398 | return retval; | 352 | return retval; |
| 399 | } | 353 | } |
| 400 | 354 | ||
| 401 | /* Puts node back in the resource list pointed to by head */ | ||
| 402 | static inline void return_resource(struct pci_resource **head, struct pci_resource *node) | ||
| 403 | { | ||
| 404 | if (!node || !head) | ||
| 405 | return; | ||
| 406 | node->next = *head; | ||
| 407 | *head = node; | ||
| 408 | } | ||
| 409 | |||
| 410 | #define SLOT_NAME_SIZE 10 | 355 | #define SLOT_NAME_SIZE 10 |
| 411 | 356 | ||
| 412 | static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot) | 357 | static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot) |
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 6f7d8a29957a..8f5da504df34 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c | |||
| @@ -418,16 +418,8 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
| 418 | goto err_out_free_ctrl_bus; | 418 | goto err_out_free_ctrl_bus; |
| 419 | } | 419 | } |
| 420 | 420 | ||
| 421 | /* Get IO, memory, and IRQ resources for new devices */ | 421 | ctrl->add_support = 1; |
| 422 | rc = shpchprm_find_available_resources(ctrl); | ||
| 423 | ctrl->add_support = !rc; | ||
| 424 | 422 | ||
| 425 | if (rc) { | ||
| 426 | dbg("shpchprm_find_available_resources = %#x\n", rc); | ||
| 427 | err("unable to locate PCI configuration resources for hot plug add.\n"); | ||
| 428 | goto err_out_free_ctrl_bus; | ||
| 429 | } | ||
| 430 | |||
| 431 | /* Setup the slot information structures */ | 423 | /* Setup the slot information structures */ |
| 432 | rc = init_slots(ctrl); | 424 | rc = init_slots(ctrl); |
| 433 | if (rc) { | 425 | if (rc) { |
| @@ -497,18 +489,6 @@ static int shpc_start_thread(void) | |||
| 497 | return retval; | 489 | return retval; |
| 498 | } | 490 | } |
| 499 | 491 | ||
| 500 | static inline void __exit | ||
| 501 | free_shpchp_res(struct pci_resource *res) | ||
| 502 | { | ||
| 503 | struct pci_resource *tres; | ||
| 504 | |||
| 505 | while (res) { | ||
| 506 | tres = res; | ||
| 507 | res = res->next; | ||
| 508 | kfree(tres); | ||
| 509 | } | ||
| 510 | } | ||
| 511 | |||
| 512 | static void __exit unload_shpchpd(void) | 492 | static void __exit unload_shpchpd(void) |
| 513 | { | 493 | { |
| 514 | struct pci_func *next; | 494 | struct pci_func *next; |
| @@ -522,11 +502,6 @@ static void __exit unload_shpchpd(void) | |||
| 522 | while (ctrl) { | 502 | while (ctrl) { |
| 523 | cleanup_slots(ctrl); | 503 | cleanup_slots(ctrl); |
| 524 | 504 | ||
| 525 | free_shpchp_res(ctrl->io_head); | ||
| 526 | free_shpchp_res(ctrl->mem_head); | ||
| 527 | free_shpchp_res(ctrl->p_mem_head); | ||
| 528 | free_shpchp_res(ctrl->bus_head); | ||
| 529 | |||
| 530 | kfree (ctrl->pci_bus); | 505 | kfree (ctrl->pci_bus); |
| 531 | 506 | ||
| 532 | dbg("%s: calling release_ctlr\n", __FUNCTION__); | 507 | dbg("%s: calling release_ctlr\n", __FUNCTION__); |
| @@ -541,11 +516,6 @@ static void __exit unload_shpchpd(void) | |||
| 541 | for (loop = 0; loop < 256; loop++) { | 516 | for (loop = 0; loop < 256; loop++) { |
| 542 | next = shpchp_slot_list[loop]; | 517 | next = shpchp_slot_list[loop]; |
| 543 | while (next != NULL) { | 518 | while (next != NULL) { |
| 544 | free_shpchp_res(next->io_head); | ||
| 545 | free_shpchp_res(next->mem_head); | ||
| 546 | free_shpchp_res(next->p_mem_head); | ||
| 547 | free_shpchp_res(next->bus_head); | ||
| 548 | |||
| 549 | TempSlot = next; | 519 | TempSlot = next; |
| 550 | next = next->next; | 520 | next = next->next; |
| 551 | kfree(TempSlot); | 521 | kfree(TempSlot); |
| @@ -607,9 +577,7 @@ error_hpc_init: | |||
| 607 | if (retval) { | 577 | if (retval) { |
| 608 | shpchprm_cleanup(); | 578 | shpchprm_cleanup(); |
| 609 | shpchp_event_stop_thread(); | 579 | shpchp_event_stop_thread(); |
| 610 | } else | 580 | } |
| 611 | shpchprm_print_pirt(); | ||
| 612 | |||
| 613 | return retval; | 581 | return retval; |
| 614 | } | 582 | } |
| 615 | 583 | ||
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 91c9903e621f..aa507e453e49 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c | |||
| @@ -38,13 +38,10 @@ | |||
| 38 | #include <linux/wait.h> | 38 | #include <linux/wait.h> |
| 39 | #include <linux/smp_lock.h> | 39 | #include <linux/smp_lock.h> |
| 40 | #include <linux/pci.h> | 40 | #include <linux/pci.h> |
| 41 | #include "../pci.h" | ||
| 41 | #include "shpchp.h" | 42 | #include "shpchp.h" |
| 42 | #include "shpchprm.h" | 43 | #include "shpchprm.h" |
| 43 | 44 | ||
| 44 | static u32 configure_new_device(struct controller *ctrl, struct pci_func *func, | ||
| 45 | u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev); | ||
| 46 | static int configure_new_function( struct controller *ctrl, struct pci_func *func, | ||
| 47 | u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev); | ||
| 48 | static void interrupt_event_handler(struct controller *ctrl); | 45 | static void interrupt_event_handler(struct controller *ctrl); |
| 49 | 46 | ||
| 50 | static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ | 47 | static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ |
| @@ -52,9 +49,6 @@ static struct semaphore event_exit; /* guard ensure thread has exited before ca | |||
| 52 | static int event_finished; | 49 | static int event_finished; |
| 53 | static unsigned long pushbutton_pending; /* = 0 */ | 50 | static unsigned long pushbutton_pending; /* = 0 */ |
| 54 | 51 | ||
| 55 | u8 shpchp_disk_irq; | ||
| 56 | u8 shpchp_nic_irq; | ||
| 57 | |||
| 58 | u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id) | 52 | u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id) |
| 59 | { | 53 | { |
| 60 | struct controller *ctrl = (struct controller *) inst_id; | 54 | struct controller *ctrl = (struct controller *) inst_id; |
| @@ -260,624 +254,6 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) | |||
| 260 | return rc; | 254 | return rc; |
| 261 | } | 255 | } |
| 262 | 256 | ||
| 263 | |||
| 264 | /* | ||
| 265 | * sort_by_size | ||
| 266 | * | ||
| 267 | * Sorts nodes on the list by their length. | ||
| 268 | * Smallest first. | ||
| 269 | * | ||
| 270 | */ | ||
| 271 | static int sort_by_size(struct pci_resource **head) | ||
| 272 | { | ||
| 273 | struct pci_resource *current_res; | ||
| 274 | struct pci_resource *next_res; | ||
| 275 | int out_of_order = 1; | ||
| 276 | |||
| 277 | if (!(*head)) | ||
| 278 | return(1); | ||
| 279 | |||
| 280 | if (!((*head)->next)) | ||
| 281 | return(0); | ||
| 282 | |||
| 283 | while (out_of_order) { | ||
| 284 | out_of_order = 0; | ||
| 285 | |||
| 286 | /* Special case for swapping list head */ | ||
| 287 | if (((*head)->next) && | ||
| 288 | ((*head)->length > (*head)->next->length)) { | ||
| 289 | out_of_order++; | ||
| 290 | current_res = *head; | ||
| 291 | *head = (*head)->next; | ||
| 292 | current_res->next = (*head)->next; | ||
| 293 | (*head)->next = current_res; | ||
| 294 | } | ||
| 295 | |||
| 296 | current_res = *head; | ||
| 297 | |||
| 298 | while (current_res->next && current_res->next->next) { | ||
| 299 | if (current_res->next->length > current_res->next->next->length) { | ||
| 300 | out_of_order++; | ||
| 301 | next_res = current_res->next; | ||
| 302 | current_res->next = current_res->next->next; | ||
| 303 | current_res = current_res->next; | ||
| 304 | next_res->next = current_res->next; | ||
| 305 | current_res->next = next_res; | ||
| 306 | } else | ||
| 307 | current_res = current_res->next; | ||
| 308 | } | ||
| 309 | } /* End of out_of_order loop */ | ||
| 310 | |||
| 311 | return(0); | ||
| 312 | } | ||
| 313 | |||
| 314 | |||
| 315 | /* | ||
| 316 | * sort_by_max_size | ||
| 317 | * | ||
| 318 | * Sorts nodes on the list by their length. | ||
| 319 | * Largest first. | ||
| 320 | * | ||
| 321 | */ | ||
| 322 | static int sort_by_max_size(struct pci_resource **head) | ||
| 323 | { | ||
| 324 | struct pci_resource *current_res; | ||
| 325 | struct pci_resource *next_res; | ||
| 326 | int out_of_order = 1; | ||
| 327 | |||
| 328 | if (!(*head)) | ||
| 329 | return(1); | ||
| 330 | |||
| 331 | if (!((*head)->next)) | ||
| 332 | return(0); | ||
| 333 | |||
| 334 | while (out_of_order) { | ||
| 335 | out_of_order = 0; | ||
| 336 | |||
| 337 | /* Special case for swapping list head */ | ||
| 338 | if (((*head)->next) && | ||
| 339 | ((*head)->length < (*head)->next->length)) { | ||
| 340 | out_of_order++; | ||
| 341 | current_res = *head; | ||
| 342 | *head = (*head)->next; | ||
| 343 | current_res->next = (*head)->next; | ||
| 344 | (*head)->next = current_res; | ||
| 345 | } | ||
| 346 | |||
| 347 | current_res = *head; | ||
| 348 | |||
| 349 | while (current_res->next && current_res->next->next) { | ||
| 350 | if (current_res->next->length < current_res->next->next->length) { | ||
| 351 | out_of_order++; | ||
| 352 | next_res = current_res->next; | ||
| 353 | current_res->next = current_res->next->next; | ||
| 354 | current_res = current_res->next; | ||
| 355 | next_res->next = current_res->next; | ||
| 356 | current_res->next = next_res; | ||
| 357 | } else | ||
| 358 | current_res = current_res->next; | ||
| 359 | } | ||
| 360 | } /* End of out_of_order loop */ | ||
| 361 | |||
| 362 | return(0); | ||
| 363 | } | ||
| 364 | |||
| 365 | |||
| 366 | /* | ||
| 367 | * do_pre_bridge_resource_split | ||
| 368 | * | ||
| 369 | * Returns zero or one node of resources that aren't in use | ||
| 370 | * | ||
| 371 | */ | ||
| 372 | static struct pci_resource *do_pre_bridge_resource_split (struct pci_resource **head, struct pci_resource **orig_head, u32 alignment) | ||
| 373 | { | ||
| 374 | struct pci_resource *prevnode = NULL; | ||
| 375 | struct pci_resource *node; | ||
| 376 | struct pci_resource *split_node; | ||
| 377 | u32 rc; | ||
| 378 | u32 temp_dword; | ||
| 379 | dbg("do_pre_bridge_resource_split\n"); | ||
| 380 | |||
| 381 | if (!(*head) || !(*orig_head)) | ||
| 382 | return(NULL); | ||
| 383 | |||
| 384 | rc = shpchp_resource_sort_and_combine(head); | ||
| 385 | |||
| 386 | if (rc) | ||
| 387 | return(NULL); | ||
| 388 | |||
| 389 | if ((*head)->base != (*orig_head)->base) | ||
| 390 | return(NULL); | ||
| 391 | |||
| 392 | if ((*head)->length == (*orig_head)->length) | ||
| 393 | return(NULL); | ||
| 394 | |||
| 395 | |||
| 396 | /* If we got here, there the bridge requires some of the resource, but | ||
| 397 | * we may be able to split some off of the front | ||
| 398 | */ | ||
| 399 | node = *head; | ||
| 400 | |||
| 401 | if (node->length & (alignment -1)) { | ||
| 402 | /* This one isn't an aligned length, so we'll make a new entry | ||
| 403 | * and split it up. | ||
| 404 | */ | ||
| 405 | split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); | ||
| 406 | |||
| 407 | if (!split_node) | ||
| 408 | return(NULL); | ||
| 409 | |||
| 410 | temp_dword = (node->length | (alignment-1)) + 1 - alignment; | ||
| 411 | |||
| 412 | split_node->base = node->base; | ||
| 413 | split_node->length = temp_dword; | ||
| 414 | |||
| 415 | node->length -= temp_dword; | ||
| 416 | node->base += split_node->length; | ||
| 417 | |||
| 418 | /* Put it in the list */ | ||
| 419 | *head = split_node; | ||
| 420 | split_node->next = node; | ||
| 421 | } | ||
| 422 | |||
| 423 | if (node->length < alignment) { | ||
| 424 | return(NULL); | ||
| 425 | } | ||
| 426 | |||
| 427 | /* Now unlink it */ | ||
| 428 | if (*head == node) { | ||
| 429 | *head = node->next; | ||
| 430 | node->next = NULL; | ||
| 431 | } else { | ||
| 432 | prevnode = *head; | ||
| 433 | while (prevnode->next != node) | ||
| 434 | prevnode = prevnode->next; | ||
| 435 | |||
| 436 | prevnode->next = node->next; | ||
| 437 | node->next = NULL; | ||
| 438 | } | ||
| 439 | |||
| 440 | return(node); | ||
| 441 | } | ||
| 442 | |||
| 443 | |||
| 444 | /* | ||
| 445 | * do_bridge_resource_split | ||
| 446 | * | ||
| 447 | * Returns zero or one node of resources that aren't in use | ||
| 448 | * | ||
| 449 | */ | ||
| 450 | static struct pci_resource *do_bridge_resource_split (struct pci_resource **head, u32 alignment) | ||
| 451 | { | ||
| 452 | struct pci_resource *prevnode = NULL; | ||
| 453 | struct pci_resource *node; | ||
| 454 | u32 rc; | ||
| 455 | u32 temp_dword; | ||
| 456 | |||
| 457 | if (!(*head)) | ||
| 458 | return(NULL); | ||
| 459 | |||
| 460 | rc = shpchp_resource_sort_and_combine(head); | ||
| 461 | |||
| 462 | if (rc) | ||
| 463 | return(NULL); | ||
| 464 | |||
| 465 | node = *head; | ||
| 466 | |||
| 467 | while (node->next) { | ||
| 468 | prevnode = node; | ||
| 469 | node = node->next; | ||
| 470 | kfree(prevnode); | ||
| 471 | } | ||
| 472 | |||
| 473 | if (node->length < alignment) { | ||
| 474 | kfree(node); | ||
| 475 | return(NULL); | ||
| 476 | } | ||
| 477 | |||
| 478 | if (node->base & (alignment - 1)) { | ||
| 479 | /* Short circuit if adjusted size is too small */ | ||
| 480 | temp_dword = (node->base | (alignment-1)) + 1; | ||
| 481 | if ((node->length - (temp_dword - node->base)) < alignment) { | ||
| 482 | kfree(node); | ||
| 483 | return(NULL); | ||
| 484 | } | ||
| 485 | |||
| 486 | node->length -= (temp_dword - node->base); | ||
| 487 | node->base = temp_dword; | ||
| 488 | } | ||
| 489 | |||
| 490 | if (node->length & (alignment - 1)) { | ||
| 491 | /* There's stuff in use after this node */ | ||
| 492 | kfree(node); | ||
| 493 | return(NULL); | ||
| 494 | } | ||
| 495 | |||
| 496 | return(node); | ||
| 497 | } | ||
| 498 | |||
| 499 | |||
| 500 | /* | ||
| 501 | * get_io_resource | ||
| 502 | * | ||
| 503 | * this function sorts the resource list by size and then | ||
| 504 | * returns the first node of "size" length that is not in the | ||
| 505 | * ISA aliasing window. If it finds a node larger than "size" | ||
| 506 | * it will split it up. | ||
| 507 | * | ||
| 508 | * size must be a power of two. | ||
| 509 | */ | ||
| 510 | static struct pci_resource *get_io_resource (struct pci_resource **head, u32 size) | ||
| 511 | { | ||
| 512 | struct pci_resource *prevnode; | ||
| 513 | struct pci_resource *node; | ||
| 514 | struct pci_resource *split_node = NULL; | ||
| 515 | u32 temp_dword; | ||
| 516 | |||
| 517 | if (!(*head)) | ||
| 518 | return(NULL); | ||
| 519 | |||
| 520 | if ( shpchp_resource_sort_and_combine(head) ) | ||
| 521 | return(NULL); | ||
| 522 | |||
| 523 | if ( sort_by_size(head) ) | ||
| 524 | return(NULL); | ||
| 525 | |||
| 526 | for (node = *head; node; node = node->next) { | ||
| 527 | if (node->length < size) | ||
| 528 | continue; | ||
| 529 | |||
| 530 | if (node->base & (size - 1)) { | ||
| 531 | /* This one isn't base aligned properly | ||
| 532 | so we'll make a new entry and split it up */ | ||
| 533 | temp_dword = (node->base | (size-1)) + 1; | ||
| 534 | |||
| 535 | /*/ Short circuit if adjusted size is too small */ | ||
| 536 | if ((node->length - (temp_dword - node->base)) < size) | ||
| 537 | continue; | ||
| 538 | |||
| 539 | split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); | ||
| 540 | |||
| 541 | if (!split_node) | ||
| 542 | return(NULL); | ||
| 543 | |||
| 544 | split_node->base = node->base; | ||
| 545 | split_node->length = temp_dword - node->base; | ||
| 546 | node->base = temp_dword; | ||
| 547 | node->length -= split_node->length; | ||
| 548 | |||
| 549 | /* Put it in the list */ | ||
| 550 | split_node->next = node->next; | ||
| 551 | node->next = split_node; | ||
| 552 | } /* End of non-aligned base */ | ||
| 553 | |||
| 554 | /* Don't need to check if too small since we already did */ | ||
| 555 | if (node->length > size) { | ||
| 556 | /* This one is longer than we need | ||
| 557 | so we'll make a new entry and split it up */ | ||
| 558 | split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); | ||
| 559 | |||
| 560 | if (!split_node) | ||
| 561 | return(NULL); | ||
| 562 | |||
| 563 | split_node->base = node->base + size; | ||
| 564 | split_node->length = node->length - size; | ||
| 565 | node->length = size; | ||
| 566 | |||
| 567 | /* Put it in the list */ | ||
| 568 | split_node->next = node->next; | ||
| 569 | node->next = split_node; | ||
| 570 | } /* End of too big on top end */ | ||
| 571 | |||
| 572 | /* For IO make sure it's not in the ISA aliasing space */ | ||
| 573 | if (node->base & 0x300L) | ||
| 574 | continue; | ||
| 575 | |||
| 576 | /* If we got here, then it is the right size | ||
| 577 | Now take it out of the list */ | ||
| 578 | if (*head == node) { | ||
| 579 | *head = node->next; | ||
| 580 | } else { | ||
| 581 | prevnode = *head; | ||
| 582 | while (prevnode->next != node) | ||
| 583 | prevnode = prevnode->next; | ||
| 584 | |||
| 585 | prevnode->next = node->next; | ||
| 586 | } | ||
| 587 | node->next = NULL; | ||
| 588 | /* Stop looping */ | ||
| 589 | break; | ||
| 590 | } | ||
| 591 | |||
| 592 | return(node); | ||
| 593 | } | ||
| 594 | |||
| 595 | |||
| 596 | /* | ||
| 597 | * get_max_resource | ||
| 598 | * | ||
| 599 | * Gets the largest node that is at least "size" big from the | ||
| 600 | * list pointed to by head. It aligns the node on top and bottom | ||
| 601 | * to "size" alignment before returning it. | ||
| 602 | * J.I. modified to put max size limits of; 64M->32M->16M->8M->4M->1M | ||
| 603 | * This is needed to avoid allocating entire ACPI _CRS res to one child bridge/slot. | ||
| 604 | */ | ||
| 605 | static struct pci_resource *get_max_resource (struct pci_resource **head, u32 size) | ||
| 606 | { | ||
| 607 | struct pci_resource *max; | ||
| 608 | struct pci_resource *temp; | ||
| 609 | struct pci_resource *split_node; | ||
| 610 | u32 temp_dword; | ||
| 611 | u32 max_size[] = { 0x4000000, 0x2000000, 0x1000000, 0x0800000, 0x0400000, 0x0200000, 0x0100000, 0x00 }; | ||
| 612 | int i; | ||
| 613 | |||
| 614 | if (!(*head)) | ||
| 615 | return(NULL); | ||
| 616 | |||
| 617 | if (shpchp_resource_sort_and_combine(head)) | ||
| 618 | return(NULL); | ||
| 619 | |||
| 620 | if (sort_by_max_size(head)) | ||
| 621 | return(NULL); | ||
| 622 | |||
| 623 | for (max = *head;max; max = max->next) { | ||
| 624 | |||
| 625 | /* If not big enough we could probably just bail, | ||
| 626 | instead we'll continue to the next. */ | ||
| 627 | if (max->length < size) | ||
| 628 | continue; | ||
| 629 | |||
| 630 | if (max->base & (size - 1)) { | ||
| 631 | /* This one isn't base aligned properly | ||
| 632 | so we'll make a new entry and split it up */ | ||
| 633 | temp_dword = (max->base | (size-1)) + 1; | ||
| 634 | |||
| 635 | /* Short circuit if adjusted size is too small */ | ||
| 636 | if ((max->length - (temp_dword - max->base)) < size) | ||
| 637 | continue; | ||
| 638 | |||
| 639 | split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); | ||
| 640 | |||
| 641 | if (!split_node) | ||
| 642 | return(NULL); | ||
| 643 | |||
| 644 | split_node->base = max->base; | ||
| 645 | split_node->length = temp_dword - max->base; | ||
| 646 | max->base = temp_dword; | ||
| 647 | max->length -= split_node->length; | ||
| 648 | |||
| 649 | /* Put it next in the list */ | ||
| 650 | split_node->next = max->next; | ||
| 651 | max->next = split_node; | ||
| 652 | } | ||
| 653 | |||
| 654 | if ((max->base + max->length) & (size - 1)) { | ||
| 655 | /* This one isn't end aligned properly at the top | ||
| 656 | so we'll make a new entry and split it up */ | ||
| 657 | split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); | ||
| 658 | |||
| 659 | if (!split_node) | ||
| 660 | return(NULL); | ||
| 661 | temp_dword = ((max->base + max->length) & ~(size - 1)); | ||
| 662 | split_node->base = temp_dword; | ||
| 663 | split_node->length = max->length + max->base | ||
| 664 | - split_node->base; | ||
| 665 | max->length -= split_node->length; | ||
| 666 | |||
| 667 | /* Put it in the list */ | ||
| 668 | split_node->next = max->next; | ||
| 669 | max->next = split_node; | ||
| 670 | } | ||
| 671 | |||
| 672 | /* Make sure it didn't shrink too much when we aligned it */ | ||
| 673 | if (max->length < size) | ||
| 674 | continue; | ||
| 675 | |||
| 676 | for ( i = 0; max_size[i] > size; i++) { | ||
| 677 | if (max->length > max_size[i]) { | ||
| 678 | split_node = kmalloc(sizeof(*split_node), | ||
| 679 | GFP_KERNEL); | ||
| 680 | if (!split_node) | ||
| 681 | break; /* return (NULL); */ | ||
| 682 | split_node->base = max->base + max_size[i]; | ||
| 683 | split_node->length = max->length - max_size[i]; | ||
| 684 | max->length = max_size[i]; | ||
| 685 | /* Put it next in the list */ | ||
| 686 | split_node->next = max->next; | ||
| 687 | max->next = split_node; | ||
| 688 | break; | ||
| 689 | } | ||
| 690 | } | ||
| 691 | |||
| 692 | /* Now take it out of the list */ | ||
| 693 | temp = (struct pci_resource*) *head; | ||
| 694 | if (temp == max) { | ||
| 695 | *head = max->next; | ||
| 696 | } else { | ||
| 697 | while (temp && temp->next != max) { | ||
| 698 | temp = temp->next; | ||
| 699 | } | ||
| 700 | |||
| 701 | temp->next = max->next; | ||
| 702 | } | ||
| 703 | |||
| 704 | max->next = NULL; | ||
| 705 | return(max); | ||
| 706 | } | ||
| 707 | |||
| 708 | /* If we get here, we couldn't find one */ | ||
| 709 | return(NULL); | ||
| 710 | } | ||
| 711 | |||
| 712 | |||
| 713 | /* | ||
| 714 | * get_resource | ||
| 715 | * | ||
| 716 | * this function sorts the resource list by size and then | ||
| 717 | * returns the first node of "size" length. If it finds a node | ||
| 718 | * larger than "size" it will split it up. | ||
| 719 | * | ||
| 720 | * size must be a power of two. | ||
| 721 | */ | ||
| 722 | static struct pci_resource *get_resource (struct pci_resource **head, u32 size) | ||
| 723 | { | ||
| 724 | struct pci_resource *prevnode; | ||
| 725 | struct pci_resource *node; | ||
| 726 | struct pci_resource *split_node; | ||
| 727 | u32 temp_dword; | ||
| 728 | |||
| 729 | if (!(*head)) | ||
| 730 | return(NULL); | ||
| 731 | |||
| 732 | if ( shpchp_resource_sort_and_combine(head) ) | ||
| 733 | return(NULL); | ||
| 734 | |||
| 735 | if ( sort_by_size(head) ) | ||
| 736 | return(NULL); | ||
| 737 | |||
| 738 | for (node = *head; node; node = node->next) { | ||
| 739 | dbg("%s: req_size =0x%x node=%p, base=0x%x, length=0x%x\n", | ||
| 740 | __FUNCTION__, size, node, node->base, node->length); | ||
| 741 | if (node->length < size) | ||
| 742 | continue; | ||
| 743 | |||
| 744 | if (node->base & (size - 1)) { | ||
| 745 | dbg("%s: not aligned\n", __FUNCTION__); | ||
| 746 | /* this one isn't base aligned properly | ||
| 747 | so we'll make a new entry and split it up */ | ||
| 748 | temp_dword = (node->base | (size-1)) + 1; | ||
| 749 | |||
| 750 | /* Short circuit if adjusted size is too small */ | ||
| 751 | if ((node->length - (temp_dword - node->base)) < size) | ||
| 752 | continue; | ||
| 753 | |||
| 754 | split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); | ||
| 755 | |||
| 756 | if (!split_node) | ||
| 757 | return(NULL); | ||
| 758 | |||
| 759 | split_node->base = node->base; | ||
| 760 | split_node->length = temp_dword - node->base; | ||
| 761 | node->base = temp_dword; | ||
| 762 | node->length -= split_node->length; | ||
| 763 | |||
| 764 | /* Put it in the list */ | ||
| 765 | split_node->next = node->next; | ||
| 766 | node->next = split_node; | ||
| 767 | } /* End of non-aligned base */ | ||
| 768 | |||
| 769 | /* Don't need to check if too small since we already did */ | ||
| 770 | if (node->length > size) { | ||
| 771 | dbg("%s: too big\n", __FUNCTION__); | ||
| 772 | /* this one is longer than we need | ||
| 773 | so we'll make a new entry and split it up */ | ||
| 774 | split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); | ||
| 775 | |||
| 776 | if (!split_node) | ||
| 777 | return(NULL); | ||
| 778 | |||
| 779 | split_node->base = node->base + size; | ||
| 780 | split_node->length = node->length - size; | ||
| 781 | node->length = size; | ||
| 782 | |||
| 783 | /* Put it in the list */ | ||
| 784 | split_node->next = node->next; | ||
| 785 | node->next = split_node; | ||
| 786 | } /* End of too big on top end */ | ||
| 787 | |||
| 788 | dbg("%s: got one!!!\n", __FUNCTION__); | ||
| 789 | /* If we got here, then it is the right size | ||
| 790 | Now take it out of the list */ | ||
| 791 | if (*head == node) { | ||
| 792 | *head = node->next; | ||
| 793 | } else { | ||
| 794 | prevnode = *head; | ||
| 795 | while (prevnode->next != node) | ||
| 796 | prevnode = prevnode->next; | ||
| 797 | |||
| 798 | prevnode->next = node->next; | ||
| 799 | } | ||
| 800 | node->next = NULL; | ||
| 801 | /* Stop looping */ | ||
| 802 | break; | ||
| 803 | } | ||
| 804 | return(node); | ||
| 805 | } | ||
| 806 | |||
| 807 | |||
| 808 | /* | ||
| 809 | * shpchp_resource_sort_and_combine | ||
| 810 | * | ||
| 811 | * Sorts all of the nodes in the list in ascending order by | ||
| 812 | * their base addresses. Also does garbage collection by | ||
| 813 | * combining adjacent nodes. | ||
| 814 | * | ||
| 815 | * returns 0 if success | ||
| 816 | */ | ||
| 817 | int shpchp_resource_sort_and_combine(struct pci_resource **head) | ||
| 818 | { | ||
| 819 | struct pci_resource *node1; | ||
| 820 | struct pci_resource *node2; | ||
| 821 | int out_of_order = 1; | ||
| 822 | |||
| 823 | dbg("%s: head = %p, *head = %p\n", __FUNCTION__, head, *head); | ||
| 824 | |||
| 825 | if (!(*head)) | ||
| 826 | return(1); | ||
| 827 | |||
| 828 | dbg("*head->next = %p\n",(*head)->next); | ||
| 829 | |||
| 830 | if (!(*head)->next) | ||
| 831 | return(0); /* only one item on the list, already sorted! */ | ||
| 832 | |||
| 833 | dbg("*head->base = 0x%x\n",(*head)->base); | ||
| 834 | dbg("*head->next->base = 0x%x\n",(*head)->next->base); | ||
| 835 | while (out_of_order) { | ||
| 836 | out_of_order = 0; | ||
| 837 | |||
| 838 | /* Special case for swapping list head */ | ||
| 839 | if (((*head)->next) && | ||
| 840 | ((*head)->base > (*head)->next->base)) { | ||
| 841 | node1 = *head; | ||
| 842 | (*head) = (*head)->next; | ||
| 843 | node1->next = (*head)->next; | ||
| 844 | (*head)->next = node1; | ||
| 845 | out_of_order++; | ||
| 846 | } | ||
| 847 | |||
| 848 | node1 = (*head); | ||
| 849 | |||
| 850 | while (node1->next && node1->next->next) { | ||
| 851 | if (node1->next->base > node1->next->next->base) { | ||
| 852 | out_of_order++; | ||
| 853 | node2 = node1->next; | ||
| 854 | node1->next = node1->next->next; | ||
| 855 | node1 = node1->next; | ||
| 856 | node2->next = node1->next; | ||
| 857 | node1->next = node2; | ||
| 858 | } else | ||
| 859 | node1 = node1->next; | ||
| 860 | } | ||
| 861 | } /* End of out_of_order loop */ | ||
| 862 | |||
| 863 | node1 = *head; | ||
| 864 | |||
| 865 | while (node1 && node1->next) { | ||
| 866 | if ((node1->base + node1->length) == node1->next->base) { | ||
| 867 | /* Combine */ | ||
| 868 | dbg("8..\n"); | ||
| 869 | node1->length += node1->next->length; | ||
| 870 | node2 = node1->next; | ||
| 871 | node1->next = node1->next->next; | ||
| 872 | kfree(node2); | ||
| 873 | } else | ||
| 874 | node1 = node1->next; | ||
| 875 | } | ||
| 876 | |||
| 877 | return(0); | ||
| 878 | } | ||
| 879 | |||
| 880 | |||
| 881 | /** | 257 | /** |
| 882 | * shpchp_slot_create - Creates a node and adds it to the proper bus. | 258 | * shpchp_slot_create - Creates a node and adds it to the proper bus. |
| 883 | * @busnumber - bus where new node is to be located | 259 | * @busnumber - bus where new node is to be located |
| @@ -933,7 +309,6 @@ static int slot_remove(struct pci_func * old_slot) | |||
| 933 | 309 | ||
| 934 | if (next == old_slot) { | 310 | if (next == old_slot) { |
| 935 | shpchp_slot_list[old_slot->bus] = old_slot->next; | 311 | shpchp_slot_list[old_slot->bus] = old_slot->next; |
| 936 | shpchp_destroy_board_resources(old_slot); | ||
| 937 | kfree(old_slot); | 312 | kfree(old_slot); |
| 938 | return(0); | 313 | return(0); |
| 939 | } | 314 | } |
| @@ -944,7 +319,6 @@ static int slot_remove(struct pci_func * old_slot) | |||
| 944 | 319 | ||
| 945 | if (next->next == old_slot) { | 320 | if (next->next == old_slot) { |
| 946 | next->next = old_slot->next; | 321 | next->next = old_slot->next; |
| 947 | shpchp_destroy_board_resources(old_slot); | ||
| 948 | kfree(old_slot); | 322 | kfree(old_slot); |
| 949 | return(0); | 323 | return(0); |
| 950 | } else | 324 | } else |
| @@ -1120,12 +494,8 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl) | |||
| 1120 | { | 494 | { |
| 1121 | u8 hp_slot; | 495 | u8 hp_slot; |
| 1122 | u8 slots_not_empty = 0; | 496 | u8 slots_not_empty = 0; |
| 1123 | int index; | 497 | u32 rc = 0; |
| 1124 | u32 temp_register = 0xFFFFFFFF; | ||
| 1125 | u32 retval, rc = 0; | ||
| 1126 | struct pci_func *new_func = NULL; | ||
| 1127 | struct slot *p_slot; | 498 | struct slot *p_slot; |
| 1128 | struct resource_lists res_lists; | ||
| 1129 | enum pci_bus_speed adapter_speed, bus_speed, max_bus_speed; | 499 | enum pci_bus_speed adapter_speed, bus_speed, max_bus_speed; |
| 1130 | u8 pi, mode; | 500 | u8 pi, mode; |
| 1131 | 501 | ||
| @@ -1328,135 +698,65 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl) | |||
| 1328 | /* Check for a power fault */ | 698 | /* Check for a power fault */ |
| 1329 | if (func->status == 0xFF) { | 699 | if (func->status == 0xFF) { |
| 1330 | /* power fault occurred, but it was benign */ | 700 | /* power fault occurred, but it was benign */ |
| 1331 | temp_register = 0xFFFFFFFF; | 701 | dbg("%s: power fault\n", __FUNCTION__); |
| 1332 | dbg("%s: temp register set to %x by power fault\n", __FUNCTION__, temp_register); | ||
| 1333 | rc = POWER_FAILURE; | 702 | rc = POWER_FAILURE; |
| 1334 | func->status = 0; | 703 | func->status = 0; |
| 1335 | } else { | 704 | goto err_exit; |
| 1336 | /* Get vendor/device ID u32 */ | ||
| 1337 | rc = pci_bus_read_config_dword (ctrl->pci_dev->subordinate, PCI_DEVFN(func->device, func->function), | ||
| 1338 | PCI_VENDOR_ID, &temp_register); | ||
| 1339 | dbg("%s: pci_bus_read_config_dword returns %d\n", __FUNCTION__, rc); | ||
| 1340 | dbg("%s: temp_register is %x\n", __FUNCTION__, temp_register); | ||
| 1341 | |||
| 1342 | if (rc != 0) { | ||
| 1343 | /* Something's wrong here */ | ||
| 1344 | temp_register = 0xFFFFFFFF; | ||
| 1345 | dbg("%s: temp register set to %x by error\n", __FUNCTION__, temp_register); | ||
| 1346 | } | ||
| 1347 | /* Preset return code. It will be changed later if things go okay. */ | ||
| 1348 | rc = NO_ADAPTER_PRESENT; | ||
| 1349 | } | 705 | } |
| 1350 | 706 | ||
| 1351 | /* All F's is an empty slot or an invalid board */ | 707 | if (shpchp_configure_device(p_slot)) { |
| 1352 | if (temp_register != 0xFFFFFFFF) { /* Check for a board in the slot */ | 708 | err("Cannot add device at 0x%x:0x%x\n", p_slot->bus, |
| 1353 | res_lists.io_head = ctrl->io_head; | 709 | p_slot->device); |
| 1354 | res_lists.mem_head = ctrl->mem_head; | 710 | goto err_exit; |
| 1355 | res_lists.p_mem_head = ctrl->p_mem_head; | 711 | } |
| 1356 | res_lists.bus_head = ctrl->bus_head; | ||
| 1357 | res_lists.irqs = NULL; | ||
| 1358 | |||
| 1359 | rc = configure_new_device(ctrl, func, 0, &res_lists, 0, 0); | ||
| 1360 | dbg("%s: back from configure_new_device\n", __FUNCTION__); | ||
| 1361 | |||
| 1362 | ctrl->io_head = res_lists.io_head; | ||
| 1363 | ctrl->mem_head = res_lists.mem_head; | ||
| 1364 | ctrl->p_mem_head = res_lists.p_mem_head; | ||
| 1365 | ctrl->bus_head = res_lists.bus_head; | ||
| 1366 | |||
| 1367 | shpchp_resource_sort_and_combine(&(ctrl->mem_head)); | ||
| 1368 | shpchp_resource_sort_and_combine(&(ctrl->p_mem_head)); | ||
| 1369 | shpchp_resource_sort_and_combine(&(ctrl->io_head)); | ||
| 1370 | shpchp_resource_sort_and_combine(&(ctrl->bus_head)); | ||
| 1371 | |||
| 1372 | if (rc) { | ||
| 1373 | /* Wait for exclusive access to hardware */ | ||
| 1374 | down(&ctrl->crit_sect); | ||
| 1375 | |||
| 1376 | /* turn off slot, turn on Amber LED, turn off Green LED */ | ||
| 1377 | retval = p_slot->hpc_ops->slot_disable(p_slot); | ||
| 1378 | if (retval) { | ||
| 1379 | err("%s: Issue of Slot Enable command failed\n", __FUNCTION__); | ||
| 1380 | /* Done with exclusive hardware access */ | ||
| 1381 | up(&ctrl->crit_sect); | ||
| 1382 | return retval; | ||
| 1383 | } | ||
| 1384 | /* Wait for the command to complete */ | ||
| 1385 | wait_for_ctrl_irq (ctrl); | ||
| 1386 | |||
| 1387 | retval = p_slot->hpc_ops->check_cmd_status(ctrl); | ||
| 1388 | if (retval) { | ||
| 1389 | err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, retval); | ||
| 1390 | /* Done with exclusive hardware access */ | ||
| 1391 | up(&ctrl->crit_sect); | ||
| 1392 | return retval; | ||
| 1393 | } | ||
| 1394 | 712 | ||
| 1395 | /* Done with exclusive hardware access */ | 713 | shpchp_save_slot_config(ctrl, func); |
| 1396 | up(&ctrl->crit_sect); | ||
| 1397 | 714 | ||
| 1398 | return(rc); | 715 | func->status = 0; |
| 1399 | } | 716 | func->switch_save = 0x10; |
| 1400 | shpchp_save_slot_config(ctrl, func); | 717 | func->is_a_board = 0x01; |
| 718 | func->pwr_save = 1; | ||
| 1401 | 719 | ||
| 1402 | func->status = 0; | 720 | /* Wait for exclusive access to hardware */ |
| 1403 | func->switch_save = 0x10; | 721 | down(&ctrl->crit_sect); |
| 1404 | func->is_a_board = 0x01; | ||
| 1405 | func->pwr_save = 1; | ||
| 1406 | 722 | ||
| 1407 | /* Next, we will instantiate the linux pci_dev structures | 723 | p_slot->hpc_ops->green_led_on(p_slot); |
| 1408 | * (with appropriate driver notification, if already present) | ||
| 1409 | */ | ||
| 1410 | index = 0; | ||
| 1411 | do { | ||
| 1412 | new_func = shpchp_slot_find(ctrl->slot_bus, func->device, index++); | ||
| 1413 | if (new_func && !new_func->pci_dev) { | ||
| 1414 | dbg("%s:call pci_hp_configure_dev\n", __FUNCTION__); | ||
| 1415 | shpchp_configure_device(ctrl, new_func); | ||
| 1416 | } | ||
| 1417 | } while (new_func); | ||
| 1418 | 724 | ||
| 1419 | /* Wait for exclusive access to hardware */ | 725 | /* Wait for the command to complete */ |
| 1420 | down(&ctrl->crit_sect); | 726 | wait_for_ctrl_irq (ctrl); |
| 1421 | 727 | ||
| 1422 | p_slot->hpc_ops->green_led_on(p_slot); | 728 | /* Done with exclusive hardware access */ |
| 729 | up(&ctrl->crit_sect); | ||
| 1423 | 730 | ||
| 1424 | /* Wait for the command to complete */ | 731 | return 0; |
| 1425 | wait_for_ctrl_irq (ctrl); | ||
| 1426 | 732 | ||
| 733 | err_exit: | ||
| 734 | /* Wait for exclusive access to hardware */ | ||
| 735 | down(&ctrl->crit_sect); | ||
| 1427 | 736 | ||
| 737 | /* turn off slot, turn on Amber LED, turn off Green LED */ | ||
| 738 | rc = p_slot->hpc_ops->slot_disable(p_slot); | ||
| 739 | if (rc) { | ||
| 740 | err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); | ||
| 1428 | /* Done with exclusive hardware access */ | 741 | /* Done with exclusive hardware access */ |
| 1429 | up(&ctrl->crit_sect); | 742 | up(&ctrl->crit_sect); |
| 743 | return rc; | ||
| 744 | } | ||
| 745 | /* Wait for the command to complete */ | ||
| 746 | wait_for_ctrl_irq (ctrl); | ||
| 1430 | 747 | ||
| 1431 | } else { | 748 | rc = p_slot->hpc_ops->check_cmd_status(ctrl); |
| 1432 | /* Wait for exclusive access to hardware */ | 749 | if (rc) { |
| 1433 | down(&ctrl->crit_sect); | 750 | err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc); |
| 1434 | |||
| 1435 | /* turn off slot, turn on Amber LED, turn off Green LED */ | ||
| 1436 | rc = p_slot->hpc_ops->slot_disable(p_slot); | ||
| 1437 | if (rc) { | ||
| 1438 | err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); | ||
| 1439 | /* Done with exclusive hardware access */ | ||
| 1440 | up(&ctrl->crit_sect); | ||
| 1441 | return rc; | ||
| 1442 | } | ||
| 1443 | /* Wait for the command to complete */ | ||
| 1444 | wait_for_ctrl_irq (ctrl); | ||
| 1445 | |||
| 1446 | rc = p_slot->hpc_ops->check_cmd_status(ctrl); | ||
| 1447 | if (rc) { | ||
| 1448 | err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc); | ||
| 1449 | /* Done with exclusive hardware access */ | ||
| 1450 | up(&ctrl->crit_sect); | ||
| 1451 | return rc; | ||
| 1452 | } | ||
| 1453 | |||
| 1454 | /* Done with exclusive hardware access */ | 751 | /* Done with exclusive hardware access */ |
| 1455 | up(&ctrl->crit_sect); | 752 | up(&ctrl->crit_sect); |
| 1456 | 753 | return rc; | |
| 1457 | return(rc); | ||
| 1458 | } | 754 | } |
| 1459 | return 0; | 755 | |
| 756 | /* Done with exclusive hardware access */ | ||
| 757 | up(&ctrl->crit_sect); | ||
| 758 | |||
| 759 | return(rc); | ||
| 1460 | } | 760 | } |
| 1461 | 761 | ||
| 1462 | 762 | ||
| @@ -1466,13 +766,9 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl) | |||
| 1466 | */ | 766 | */ |
| 1467 | static u32 remove_board(struct pci_func *func, struct controller *ctrl) | 767 | static u32 remove_board(struct pci_func *func, struct controller *ctrl) |
| 1468 | { | 768 | { |
| 1469 | int index; | ||
| 1470 | u8 skip = 0; | ||
| 1471 | u8 device; | 769 | u8 device; |
| 1472 | u8 hp_slot; | 770 | u8 hp_slot; |
| 1473 | u32 rc; | 771 | u32 rc; |
| 1474 | struct resource_lists res_lists; | ||
| 1475 | struct pci_func *temp_func; | ||
| 1476 | struct slot *p_slot; | 772 | struct slot *p_slot; |
| 1477 | 773 | ||
| 1478 | if (func == NULL) | 774 | if (func == NULL) |
| @@ -1488,27 +784,6 @@ static u32 remove_board(struct pci_func *func, struct controller *ctrl) | |||
| 1488 | 784 | ||
| 1489 | dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); | 785 | dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); |
| 1490 | 786 | ||
| 1491 | if ((ctrl->add_support) && | ||
| 1492 | !(func->bus_head || func->mem_head || func->p_mem_head || func->io_head)) { | ||
| 1493 | /* Here we check to see if we've saved any of the board's | ||
| 1494 | * resources already. If so, we'll skip the attempt to | ||
| 1495 | * determine what's being used. | ||
| 1496 | */ | ||
| 1497 | index = 0; | ||
| 1498 | |||
| 1499 | temp_func = func; | ||
| 1500 | |||
| 1501 | while ((temp_func = shpchp_slot_find(temp_func->bus, temp_func->device, index++))) { | ||
| 1502 | if (temp_func->bus_head || temp_func->mem_head | ||
| 1503 | || temp_func->p_mem_head || temp_func->io_head) { | ||
| 1504 | skip = 1; | ||
| 1505 | break; | ||
| 1506 | } | ||
| 1507 | } | ||
| 1508 | |||
| 1509 | if (!skip) | ||
| 1510 | rc = shpchp_save_used_resources(ctrl, func, DISABLE_CARD); | ||
| 1511 | } | ||
| 1512 | /* Change status to shutdown */ | 787 | /* Change status to shutdown */ |
| 1513 | if (func->is_a_board) | 788 | if (func->is_a_board) |
| 1514 | func->status = 0x01; | 789 | func->status = 0x01; |
| @@ -1551,26 +826,6 @@ static u32 remove_board(struct pci_func *func, struct controller *ctrl) | |||
| 1551 | 826 | ||
| 1552 | if (ctrl->add_support) { | 827 | if (ctrl->add_support) { |
| 1553 | while (func) { | 828 | while (func) { |
| 1554 | res_lists.io_head = ctrl->io_head; | ||
| 1555 | res_lists.mem_head = ctrl->mem_head; | ||
| 1556 | res_lists.p_mem_head = ctrl->p_mem_head; | ||
| 1557 | res_lists.bus_head = ctrl->bus_head; | ||
| 1558 | |||
| 1559 | dbg("Returning resources to ctlr lists for (B/D/F) = (%#x/%#x/%#x)\n", func->bus, | ||
| 1560 | func->device, func->function); | ||
| 1561 | |||
| 1562 | shpchp_return_board_resources(func, &res_lists); | ||
| 1563 | |||
| 1564 | ctrl->io_head = res_lists.io_head; | ||
| 1565 | ctrl->mem_head = res_lists.mem_head; | ||
| 1566 | ctrl->p_mem_head = res_lists.p_mem_head; | ||
| 1567 | ctrl->bus_head = res_lists.bus_head; | ||
| 1568 | |||
| 1569 | shpchp_resource_sort_and_combine(&(ctrl->mem_head)); | ||
| 1570 | shpchp_resource_sort_and_combine(&(ctrl->p_mem_head)); | ||
| 1571 | shpchp_resource_sort_and_combine(&(ctrl->io_head)); | ||
| 1572 | shpchp_resource_sort_and_combine(&(ctrl->bus_head)); | ||
| 1573 | |||
| 1574 | if (is_bridge(func)) { | 829 | if (is_bridge(func)) { |
| 1575 | dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, | 830 | dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, |
| 1576 | func->device, func->function); | 831 | func->device, func->function); |
| @@ -2050,798 +1305,3 @@ int shpchp_disable_slot (struct slot *p_slot) | |||
| 2050 | return rc; | 1305 | return rc; |
| 2051 | } | 1306 | } |
| 2052 | 1307 | ||
| 2053 | |||
| 2054 | /** | ||
| 2055 | * configure_new_device - Configures the PCI header information of one board. | ||
| 2056 | * | ||
| 2057 | * @ctrl: pointer to controller structure | ||
| 2058 | * @func: pointer to function structure | ||
| 2059 | * @behind_bridge: 1 if this is a recursive call, 0 if not | ||
| 2060 | * @resources: pointer to set of resource lists | ||
| 2061 | * | ||
| 2062 | * Returns 0 if success | ||
| 2063 | * | ||
| 2064 | */ | ||
| 2065 | static u32 configure_new_device (struct controller * ctrl, struct pci_func * func, | ||
| 2066 | u8 behind_bridge, struct resource_lists * resources, u8 bridge_bus, u8 bridge_dev) | ||
| 2067 | { | ||
| 2068 | u8 temp_byte, function, max_functions, stop_it; | ||
| 2069 | int rc; | ||
| 2070 | u32 ID; | ||
| 2071 | struct pci_func *new_slot; | ||
| 2072 | struct pci_bus lpci_bus, *pci_bus; | ||
| 2073 | int index; | ||
| 2074 | |||
| 2075 | new_slot = func; | ||
| 2076 | |||
| 2077 | dbg("%s\n", __FUNCTION__); | ||
| 2078 | memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); | ||
| 2079 | pci_bus = &lpci_bus; | ||
| 2080 | pci_bus->number = func->bus; | ||
| 2081 | |||
| 2082 | /* Check for Multi-function device */ | ||
| 2083 | rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(func->device, func->function), 0x0E, &temp_byte); | ||
| 2084 | if (rc) { | ||
| 2085 | dbg("%s: rc = %d\n", __FUNCTION__, rc); | ||
| 2086 | return rc; | ||
| 2087 | } | ||
| 2088 | |||
| 2089 | if (temp_byte & 0x80) /* Multi-function device */ | ||
| 2090 | max_functions = 8; | ||
| 2091 | else | ||
| 2092 | max_functions = 1; | ||
| 2093 | |||
| 2094 | function = 0; | ||
| 2095 | |||
| 2096 | do { | ||
| 2097 | rc = configure_new_function(ctrl, new_slot, behind_bridge, resources, bridge_bus, bridge_dev); | ||
| 2098 | |||
| 2099 | if (rc) { | ||
| 2100 | dbg("configure_new_function failed %d\n",rc); | ||
| 2101 | index = 0; | ||
| 2102 | |||
| 2103 | while (new_slot) { | ||
| 2104 | new_slot = shpchp_slot_find(new_slot->bus, new_slot->device, index++); | ||
| 2105 | |||
| 2106 | if (new_slot) | ||
| 2107 | shpchp_return_board_resources(new_slot, resources); | ||
| 2108 | } | ||
| 2109 | |||
| 2110 | return(rc); | ||
| 2111 | } | ||
| 2112 | |||
| 2113 | function++; | ||
| 2114 | |||
| 2115 | stop_it = 0; | ||
| 2116 | |||
| 2117 | /* The following loop skips to the next present function | ||
| 2118 | * and creates a board structure | ||
| 2119 | */ | ||
| 2120 | |||
| 2121 | while ((function < max_functions) && (!stop_it)) { | ||
| 2122 | pci_bus_read_config_dword(pci_bus, PCI_DEVFN(func->device, function), 0x00, &ID); | ||
| 2123 | |||
| 2124 | if (ID == 0xFFFFFFFF) { /* There's nothing there. */ | ||
| 2125 | function++; | ||
| 2126 | } else { /* There's something there */ | ||
| 2127 | /* Setup slot structure. */ | ||
| 2128 | new_slot = shpchp_slot_create(func->bus); | ||
| 2129 | |||
| 2130 | if (new_slot == NULL) { | ||
| 2131 | /* Out of memory */ | ||
| 2132 | return(1); | ||
| 2133 | } | ||
| 2134 | |||
| 2135 | new_slot->bus = func->bus; | ||
| 2136 | new_slot->device = func->device; | ||
| 2137 | new_slot->function = function; | ||
| 2138 | new_slot->is_a_board = 1; | ||
| 2139 | new_slot->status = 0; | ||
| 2140 | |||
| 2141 | stop_it++; | ||
| 2142 | } | ||
| 2143 | } | ||
| 2144 | |||
| 2145 | } while (function < max_functions); | ||
| 2146 | dbg("returning from configure_new_device\n"); | ||
| 2147 | |||
| 2148 | return 0; | ||
| 2149 | } | ||
| 2150 | |||
| 2151 | |||
| 2152 | /* | ||
| 2153 | * Configuration logic that involves the hotplug data structures and | ||
| 2154 | * their bookkeeping | ||
| 2155 | */ | ||
| 2156 | |||
| 2157 | |||
| 2158 | /** | ||
| 2159 | * configure_new_function - Configures the PCI header information of one device | ||
| 2160 | * | ||
| 2161 | * @ctrl: pointer to controller structure | ||
| 2162 | * @func: pointer to function structure | ||
| 2163 | * @behind_bridge: 1 if this is a recursive call, 0 if not | ||
| 2164 | * @resources: pointer to set of resource lists | ||
| 2165 | * | ||
| 2166 | * Calls itself recursively for bridged devices. | ||
| 2167 | * Returns 0 if success | ||
| 2168 | * | ||
| 2169 | */ | ||
| 2170 | static int configure_new_function (struct controller * ctrl, struct pci_func * func, | ||
| 2171 | u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev) | ||
| 2172 | { | ||
| 2173 | int cloop; | ||
| 2174 | u8 temp_byte; | ||
| 2175 | u8 device; | ||
| 2176 | u8 class_code; | ||
| 2177 | u16 temp_word; | ||
| 2178 | u32 rc; | ||
| 2179 | u32 temp_register; | ||
| 2180 | u32 base; | ||
| 2181 | u32 ID; | ||
| 2182 | unsigned int devfn; | ||
| 2183 | struct pci_resource *mem_node; | ||
| 2184 | struct pci_resource *p_mem_node; | ||
| 2185 | struct pci_resource *io_node; | ||
| 2186 | struct pci_resource *bus_node; | ||
| 2187 | struct pci_resource *hold_mem_node; | ||
| 2188 | struct pci_resource *hold_p_mem_node; | ||
| 2189 | struct pci_resource *hold_IO_node; | ||
| 2190 | struct pci_resource *hold_bus_node; | ||
| 2191 | struct irq_mapping irqs; | ||
| 2192 | struct pci_func *new_slot; | ||
| 2193 | struct pci_bus lpci_bus, *pci_bus; | ||
| 2194 | struct resource_lists temp_resources; | ||
| 2195 | #if defined(CONFIG_X86_64) | ||
| 2196 | u8 IRQ=0; | ||
| 2197 | #endif | ||
| 2198 | |||
| 2199 | memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); | ||
| 2200 | pci_bus = &lpci_bus; | ||
| 2201 | pci_bus->number = func->bus; | ||
| 2202 | devfn = PCI_DEVFN(func->device, func->function); | ||
| 2203 | |||
| 2204 | /* Check for Bridge */ | ||
| 2205 | rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &temp_byte); | ||
| 2206 | if (rc) | ||
| 2207 | return rc; | ||
| 2208 | |||
| 2209 | if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */ | ||
| 2210 | /* set Primary bus */ | ||
| 2211 | dbg("set Primary bus = 0x%x\n", func->bus); | ||
| 2212 | rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func->bus); | ||
| 2213 | if (rc) | ||
| 2214 | return rc; | ||
| 2215 | |||
| 2216 | /* find range of busses to use */ | ||
| 2217 | bus_node = get_max_resource(&resources->bus_head, 1L); | ||
| 2218 | |||
| 2219 | /* If we don't have any busses to allocate, we can't continue */ | ||
| 2220 | if (!bus_node) { | ||
| 2221 | err("Got NO bus resource to use\n"); | ||
| 2222 | return -ENOMEM; | ||
| 2223 | } | ||
| 2224 | dbg("Got ranges of buses to use: base:len=0x%x:%x\n", bus_node->base, bus_node->length); | ||
| 2225 | |||
| 2226 | /* set Secondary bus */ | ||
| 2227 | temp_byte = (u8)bus_node->base; | ||
| 2228 | dbg("set Secondary bus = 0x%x\n", temp_byte); | ||
| 2229 | rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, temp_byte); | ||
| 2230 | if (rc) | ||
| 2231 | return rc; | ||
| 2232 | |||
| 2233 | /* set subordinate bus */ | ||
| 2234 | temp_byte = (u8)(bus_node->base + bus_node->length - 1); | ||
| 2235 | dbg("set subordinate bus = 0x%x\n", temp_byte); | ||
| 2236 | rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte); | ||
| 2237 | if (rc) | ||
| 2238 | return rc; | ||
| 2239 | |||
| 2240 | /* Set HP parameters (Cache Line Size, Latency Timer) */ | ||
| 2241 | rc = shpchprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_BRIDGE); | ||
| 2242 | if (rc) | ||
| 2243 | return rc; | ||
| 2244 | |||
| 2245 | /* Setup the IO, memory, and prefetchable windows */ | ||
| 2246 | |||
| 2247 | io_node = get_max_resource(&(resources->io_head), 0x1000L); | ||
| 2248 | if (io_node) { | ||
| 2249 | dbg("io_node(base, len, next) (%x, %x, %p)\n", io_node->base, io_node->length, io_node->next); | ||
| 2250 | } | ||
| 2251 | |||
| 2252 | mem_node = get_max_resource(&(resources->mem_head), 0x100000L); | ||
| 2253 | if (mem_node) { | ||
| 2254 | dbg("mem_node(base, len, next) (%x, %x, %p)\n", mem_node->base, mem_node->length, mem_node->next); | ||
| 2255 | } | ||
| 2256 | |||
| 2257 | if (resources->p_mem_head) | ||
| 2258 | p_mem_node = get_max_resource(&(resources->p_mem_head), 0x100000L); | ||
| 2259 | else { | ||
| 2260 | /* | ||
| 2261 | * In some platform implementation, MEM and PMEM are not | ||
| 2262 | * distinguished, and hence ACPI _CRS has only MEM entries | ||
| 2263 | * for both MEM and PMEM. | ||
| 2264 | */ | ||
| 2265 | dbg("using MEM for PMEM\n"); | ||
| 2266 | p_mem_node = get_max_resource(&(resources->mem_head), 0x100000L); | ||
| 2267 | } | ||
| 2268 | if (p_mem_node) { | ||
| 2269 | dbg("p_mem_node(base, len, next) (%x, %x, %p)\n", p_mem_node->base, p_mem_node->length, p_mem_node->next); | ||
| 2270 | } | ||
| 2271 | |||
| 2272 | /* set up the IRQ info */ | ||
| 2273 | if (!resources->irqs) { | ||
| 2274 | irqs.barber_pole = 0; | ||
| 2275 | irqs.interrupt[0] = 0; | ||
| 2276 | irqs.interrupt[1] = 0; | ||
| 2277 | irqs.interrupt[2] = 0; | ||
| 2278 | irqs.interrupt[3] = 0; | ||
| 2279 | irqs.valid_INT = 0; | ||
| 2280 | } else { | ||
| 2281 | irqs.barber_pole = resources->irqs->barber_pole; | ||
| 2282 | irqs.interrupt[0] = resources->irqs->interrupt[0]; | ||
| 2283 | irqs.interrupt[1] = resources->irqs->interrupt[1]; | ||
| 2284 | irqs.interrupt[2] = resources->irqs->interrupt[2]; | ||
| 2285 | irqs.interrupt[3] = resources->irqs->interrupt[3]; | ||
| 2286 | irqs.valid_INT = resources->irqs->valid_INT; | ||
| 2287 | } | ||
| 2288 | |||
| 2289 | /* set up resource lists that are now aligned on top and bottom | ||
| 2290 | * for anything behind the bridge. | ||
| 2291 | */ | ||
| 2292 | temp_resources.bus_head = bus_node; | ||
| 2293 | temp_resources.io_head = io_node; | ||
| 2294 | temp_resources.mem_head = mem_node; | ||
| 2295 | temp_resources.p_mem_head = p_mem_node; | ||
| 2296 | temp_resources.irqs = &irqs; | ||
| 2297 | |||
| 2298 | /* Make copies of the nodes we are going to pass down so that | ||
| 2299 | * if there is a problem,we can just use these to free resources | ||
| 2300 | */ | ||
| 2301 | hold_bus_node = kmalloc(sizeof(*hold_bus_node), GFP_KERNEL); | ||
| 2302 | hold_IO_node = kmalloc(sizeof(*hold_IO_node), GFP_KERNEL); | ||
| 2303 | hold_mem_node = kmalloc(sizeof(*hold_mem_node), GFP_KERNEL); | ||
| 2304 | hold_p_mem_node = kmalloc(sizeof(*hold_p_mem_node), GFP_KERNEL); | ||
| 2305 | |||
| 2306 | if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) { | ||
| 2307 | kfree(hold_bus_node); | ||
| 2308 | kfree(hold_IO_node); | ||
| 2309 | kfree(hold_mem_node); | ||
| 2310 | kfree(hold_p_mem_node); | ||
| 2311 | |||
| 2312 | return 1; | ||
| 2313 | } | ||
| 2314 | |||
| 2315 | memcpy(hold_bus_node, bus_node, sizeof(struct pci_resource)); | ||
| 2316 | |||
| 2317 | bus_node->base += 1; | ||
| 2318 | bus_node->length -= 1; | ||
| 2319 | bus_node->next = NULL; | ||
| 2320 | |||
| 2321 | /* If we have IO resources copy them and fill in the bridge's | ||
| 2322 | * IO range registers | ||
| 2323 | */ | ||
| 2324 | if (io_node) { | ||
| 2325 | memcpy(hold_IO_node, io_node, sizeof(struct pci_resource)); | ||
| 2326 | io_node->next = NULL; | ||
| 2327 | |||
| 2328 | /* set IO base and Limit registers */ | ||
| 2329 | RES_CHECK(io_node->base, 8); | ||
| 2330 | temp_byte = (u8)(io_node->base >> 8); | ||
| 2331 | rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_BASE, temp_byte); | ||
| 2332 | |||
| 2333 | RES_CHECK(io_node->base + io_node->length - 1, 8); | ||
| 2334 | temp_byte = (u8)((io_node->base + io_node->length - 1) >> 8); | ||
| 2335 | rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte); | ||
| 2336 | } else { | ||
| 2337 | kfree(hold_IO_node); | ||
| 2338 | hold_IO_node = NULL; | ||
| 2339 | } | ||
| 2340 | |||
| 2341 | /* If we have memory resources copy them and fill in the bridge's | ||
| 2342 | * memory range registers. Otherwise, fill in the range | ||
| 2343 | * registers with values that disable them. | ||
| 2344 | */ | ||
| 2345 | if (mem_node) { | ||
| 2346 | memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource)); | ||
| 2347 | mem_node->next = NULL; | ||
| 2348 | |||
| 2349 | /* set Mem base and Limit registers */ | ||
| 2350 | RES_CHECK(mem_node->base, 16); | ||
| 2351 | temp_word = (u32)(mem_node->base >> 16); | ||
| 2352 | rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_BASE, temp_word); | ||
| 2353 | |||
| 2354 | RES_CHECK(mem_node->base + mem_node->length - 1, 16); | ||
| 2355 | temp_word = (u32)((mem_node->base + mem_node->length - 1) >> 16); | ||
| 2356 | rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); | ||
| 2357 | } else { | ||
| 2358 | temp_word = 0xFFFF; | ||
| 2359 | rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_BASE, temp_word); | ||
| 2360 | |||
| 2361 | temp_word = 0x0000; | ||
| 2362 | rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); | ||
| 2363 | |||
| 2364 | kfree(hold_mem_node); | ||
| 2365 | hold_mem_node = NULL; | ||
| 2366 | } | ||
| 2367 | |||
| 2368 | /* If we have prefetchable memory resources copy them and | ||
| 2369 | * fill in the bridge's memory range registers. Otherwise, | ||
| 2370 | * fill in the range registers with values that disable them. | ||
| 2371 | */ | ||
| 2372 | if (p_mem_node) { | ||
| 2373 | memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource)); | ||
| 2374 | p_mem_node->next = NULL; | ||
| 2375 | |||
| 2376 | /* set Pre Mem base and Limit registers */ | ||
| 2377 | RES_CHECK(p_mem_node->base, 16); | ||
| 2378 | temp_word = (u32)(p_mem_node->base >> 16); | ||
| 2379 | rc = pci_bus_write_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); | ||
| 2380 | |||
| 2381 | RES_CHECK(p_mem_node->base + p_mem_node->length - 1, 16); | ||
| 2382 | temp_word = (u32)((p_mem_node->base + p_mem_node->length - 1) >> 16); | ||
| 2383 | rc = pci_bus_write_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); | ||
| 2384 | } else { | ||
| 2385 | temp_word = 0xFFFF; | ||
| 2386 | rc = pci_bus_write_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); | ||
| 2387 | |||
| 2388 | temp_word = 0x0000; | ||
| 2389 | rc = pci_bus_write_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); | ||
| 2390 | |||
| 2391 | kfree(hold_p_mem_node); | ||
| 2392 | hold_p_mem_node = NULL; | ||
| 2393 | } | ||
| 2394 | |||
| 2395 | /* Adjust this to compensate for extra adjustment in first loop */ | ||
| 2396 | irqs.barber_pole--; | ||
| 2397 | |||
| 2398 | rc = 0; | ||
| 2399 | |||
| 2400 | /* Here we actually find the devices and configure them */ | ||
| 2401 | for (device = 0; (device <= 0x1F) && !rc; device++) { | ||
| 2402 | irqs.barber_pole = (irqs.barber_pole + 1) & 0x03; | ||
| 2403 | |||
| 2404 | ID = 0xFFFFFFFF; | ||
| 2405 | pci_bus->number = hold_bus_node->base; | ||
| 2406 | pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, 0), | ||
| 2407 | PCI_VENDOR_ID, &ID); | ||
| 2408 | pci_bus->number = func->bus; | ||
| 2409 | |||
| 2410 | if (ID != 0xFFFFFFFF) { /* device Present */ | ||
| 2411 | /* Setup slot structure. */ | ||
| 2412 | new_slot = shpchp_slot_create(hold_bus_node->base); | ||
| 2413 | |||
| 2414 | if (new_slot == NULL) { | ||
| 2415 | /* Out of memory */ | ||
| 2416 | rc = -ENOMEM; | ||
| 2417 | continue; | ||
| 2418 | } | ||
| 2419 | |||
| 2420 | new_slot->bus = hold_bus_node->base; | ||
| 2421 | new_slot->device = device; | ||
| 2422 | new_slot->function = 0; | ||
| 2423 | new_slot->is_a_board = 1; | ||
| 2424 | new_slot->status = 0; | ||
| 2425 | |||
| 2426 | rc = configure_new_device(ctrl, new_slot, 1, &temp_resources, func->bus, func->device); | ||
| 2427 | dbg("configure_new_device rc=0x%x\n",rc); | ||
| 2428 | } /* End of IF (device in slot?) */ | ||
| 2429 | } /* End of FOR loop */ | ||
| 2430 | |||
| 2431 | if (rc) { | ||
| 2432 | shpchp_destroy_resource_list(&temp_resources); | ||
| 2433 | |||
| 2434 | return_resource(&(resources->bus_head), hold_bus_node); | ||
| 2435 | return_resource(&(resources->io_head), hold_IO_node); | ||
| 2436 | return_resource(&(resources->mem_head), hold_mem_node); | ||
| 2437 | return_resource(&(resources->p_mem_head), hold_p_mem_node); | ||
| 2438 | return(rc); | ||
| 2439 | } | ||
| 2440 | |||
| 2441 | /* save the interrupt routing information */ | ||
| 2442 | if (resources->irqs) { | ||
| 2443 | resources->irqs->interrupt[0] = irqs.interrupt[0]; | ||
| 2444 | resources->irqs->interrupt[1] = irqs.interrupt[1]; | ||
| 2445 | resources->irqs->interrupt[2] = irqs.interrupt[2]; | ||
| 2446 | resources->irqs->interrupt[3] = irqs.interrupt[3]; | ||
| 2447 | resources->irqs->valid_INT = irqs.valid_INT; | ||
| 2448 | } else if (!behind_bridge) { | ||
| 2449 | /* We need to hook up the interrupts here */ | ||
| 2450 | for (cloop = 0; cloop < 4; cloop++) { | ||
| 2451 | if (irqs.valid_INT & (0x01 << cloop)) { | ||
| 2452 | rc = shpchp_set_irq(func->bus, func->device, | ||
| 2453 | 0x0A + cloop, irqs.interrupt[cloop]); | ||
| 2454 | if (rc) { | ||
| 2455 | shpchp_destroy_resource_list (&temp_resources); | ||
| 2456 | return_resource(&(resources->bus_head), hold_bus_node); | ||
| 2457 | return_resource(&(resources->io_head), hold_IO_node); | ||
| 2458 | return_resource(&(resources->mem_head), hold_mem_node); | ||
| 2459 | return_resource(&(resources->p_mem_head), hold_p_mem_node); | ||
| 2460 | return rc; | ||
| 2461 | } | ||
| 2462 | } | ||
| 2463 | } /* end of for loop */ | ||
| 2464 | } | ||
| 2465 | |||
| 2466 | /* Return unused bus resources | ||
| 2467 | * First use the temporary node to store information for the board | ||
| 2468 | */ | ||
| 2469 | if (hold_bus_node && bus_node && temp_resources.bus_head) { | ||
| 2470 | hold_bus_node->length = bus_node->base - hold_bus_node->base; | ||
| 2471 | |||
| 2472 | hold_bus_node->next = func->bus_head; | ||
| 2473 | func->bus_head = hold_bus_node; | ||
| 2474 | |||
| 2475 | temp_byte = (u8)(temp_resources.bus_head->base - 1); | ||
| 2476 | |||
| 2477 | /* set subordinate bus */ | ||
| 2478 | dbg("re-set subordinate bus = 0x%x\n", temp_byte); | ||
| 2479 | rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte); | ||
| 2480 | |||
| 2481 | if (temp_resources.bus_head->length == 0) { | ||
| 2482 | kfree(temp_resources.bus_head); | ||
| 2483 | temp_resources.bus_head = NULL; | ||
| 2484 | } else { | ||
| 2485 | dbg("return bus res of b:d(0x%x:%x) base:len(0x%x:%x)\n", | ||
| 2486 | func->bus, func->device, temp_resources.bus_head->base, temp_resources.bus_head->length); | ||
| 2487 | return_resource(&(resources->bus_head), temp_resources.bus_head); | ||
| 2488 | } | ||
| 2489 | } | ||
| 2490 | |||
| 2491 | /* If we have IO space available and there is some left, | ||
| 2492 | * return the unused portion | ||
| 2493 | */ | ||
| 2494 | if (hold_IO_node && temp_resources.io_head) { | ||
| 2495 | io_node = do_pre_bridge_resource_split(&(temp_resources.io_head), | ||
| 2496 | &hold_IO_node, 0x1000); | ||
| 2497 | |||
| 2498 | /* Check if we were able to split something off */ | ||
| 2499 | if (io_node) { | ||
| 2500 | hold_IO_node->base = io_node->base + io_node->length; | ||
| 2501 | |||
| 2502 | RES_CHECK(hold_IO_node->base, 8); | ||
| 2503 | temp_byte = (u8)((hold_IO_node->base) >> 8); | ||
| 2504 | rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte); | ||
| 2505 | |||
| 2506 | return_resource(&(resources->io_head), io_node); | ||
| 2507 | } | ||
| 2508 | |||
| 2509 | io_node = do_bridge_resource_split(&(temp_resources.io_head), 0x1000); | ||
| 2510 | |||
| 2511 | /* Check if we were able to split something off */ | ||
| 2512 | if (io_node) { | ||
| 2513 | /* First use the temporary node to store information for the board */ | ||
| 2514 | hold_IO_node->length = io_node->base - hold_IO_node->base; | ||
| 2515 | |||
| 2516 | /* If we used any, add it to the board's list */ | ||
| 2517 | if (hold_IO_node->length) { | ||
| 2518 | hold_IO_node->next = func->io_head; | ||
| 2519 | func->io_head = hold_IO_node; | ||
| 2520 | |||
| 2521 | RES_CHECK(io_node->base - 1, 8); | ||
| 2522 | temp_byte = (u8)((io_node->base - 1) >> 8); | ||
| 2523 | rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte); | ||
| 2524 | |||
| 2525 | return_resource(&(resources->io_head), io_node); | ||
| 2526 | } else { | ||
| 2527 | /* it doesn't need any IO */ | ||
| 2528 | temp_byte = 0x00; | ||
| 2529 | rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte); | ||
| 2530 | |||
| 2531 | return_resource(&(resources->io_head), io_node); | ||
| 2532 | kfree(hold_IO_node); | ||
| 2533 | } | ||
| 2534 | } else { | ||
| 2535 | /* it used most of the range */ | ||
| 2536 | hold_IO_node->next = func->io_head; | ||
| 2537 | func->io_head = hold_IO_node; | ||
| 2538 | } | ||
| 2539 | } else if (hold_IO_node) { | ||
| 2540 | /* it used the whole range */ | ||
| 2541 | hold_IO_node->next = func->io_head; | ||
| 2542 | func->io_head = hold_IO_node; | ||
| 2543 | } | ||
| 2544 | |||
| 2545 | /* If we have memory space available and there is some left, | ||
| 2546 | * return the unused portion | ||
| 2547 | */ | ||
| 2548 | if (hold_mem_node && temp_resources.mem_head) { | ||
| 2549 | mem_node = do_pre_bridge_resource_split(&(temp_resources.mem_head), &hold_mem_node, 0x100000L); | ||
| 2550 | |||
| 2551 | /* Check if we were able to split something off */ | ||
| 2552 | if (mem_node) { | ||
| 2553 | hold_mem_node->base = mem_node->base + mem_node->length; | ||
| 2554 | |||
| 2555 | RES_CHECK(hold_mem_node->base, 16); | ||
| 2556 | temp_word = (u32)((hold_mem_node->base) >> 16); | ||
| 2557 | rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); | ||
| 2558 | |||
| 2559 | return_resource(&(resources->mem_head), mem_node); | ||
| 2560 | } | ||
| 2561 | |||
| 2562 | mem_node = do_bridge_resource_split(&(temp_resources.mem_head), 0x100000L); | ||
| 2563 | |||
| 2564 | /* Check if we were able to split something off */ | ||
| 2565 | if (mem_node) { | ||
| 2566 | /* First use the temporary node to store information for the board */ | ||
| 2567 | hold_mem_node->length = mem_node->base - hold_mem_node->base; | ||
| 2568 | |||
| 2569 | if (hold_mem_node->length) { | ||
| 2570 | hold_mem_node->next = func->mem_head; | ||
| 2571 | func->mem_head = hold_mem_node; | ||
| 2572 | |||
| 2573 | /* configure end address */ | ||
| 2574 | RES_CHECK(mem_node->base - 1, 16); | ||
| 2575 | temp_word = (u32)((mem_node->base - 1) >> 16); | ||
| 2576 | rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); | ||
| 2577 | |||
| 2578 | /* Return unused resources to the pool */ | ||
| 2579 | return_resource(&(resources->mem_head), mem_node); | ||
| 2580 | } else { | ||
| 2581 | /* it doesn't need any Mem */ | ||
| 2582 | temp_word = 0x0000; | ||
| 2583 | rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); | ||
| 2584 | |||
| 2585 | return_resource(&(resources->mem_head), mem_node); | ||
| 2586 | kfree(hold_mem_node); | ||
| 2587 | } | ||
| 2588 | } else { | ||
| 2589 | /* it used most of the range */ | ||
| 2590 | hold_mem_node->next = func->mem_head; | ||
| 2591 | func->mem_head = hold_mem_node; | ||
| 2592 | } | ||
| 2593 | } else if (hold_mem_node) { | ||
| 2594 | /* it used the whole range */ | ||
| 2595 | hold_mem_node->next = func->mem_head; | ||
| 2596 | func->mem_head = hold_mem_node; | ||
| 2597 | } | ||
| 2598 | |||
| 2599 | /* If we have prefetchable memory space available and there is some | ||
| 2600 | * left at the end, return the unused portion | ||
| 2601 | */ | ||
| 2602 | if (hold_p_mem_node && temp_resources.p_mem_head) { | ||
| 2603 | p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head), | ||
| 2604 | &hold_p_mem_node, 0x100000L); | ||
| 2605 | |||
| 2606 | /* Check if we were able to split something off */ | ||
| 2607 | if (p_mem_node) { | ||
| 2608 | hold_p_mem_node->base = p_mem_node->base + p_mem_node->length; | ||
| 2609 | |||
| 2610 | RES_CHECK(hold_p_mem_node->base, 16); | ||
| 2611 | temp_word = (u32)((hold_p_mem_node->base) >> 16); | ||
| 2612 | rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); | ||
| 2613 | |||
| 2614 | return_resource(&(resources->p_mem_head), p_mem_node); | ||
| 2615 | } | ||
| 2616 | |||
| 2617 | p_mem_node = do_bridge_resource_split(&(temp_resources.p_mem_head), 0x100000L); | ||
| 2618 | |||
| 2619 | /* Check if we were able to split something off */ | ||
| 2620 | if (p_mem_node) { | ||
| 2621 | /* First use the temporary node to store information for the board */ | ||
| 2622 | hold_p_mem_node->length = p_mem_node->base - hold_p_mem_node->base; | ||
| 2623 | |||
| 2624 | /* If we used any, add it to the board's list */ | ||
| 2625 | if (hold_p_mem_node->length) { | ||
| 2626 | hold_p_mem_node->next = func->p_mem_head; | ||
| 2627 | func->p_mem_head = hold_p_mem_node; | ||
| 2628 | |||
| 2629 | RES_CHECK(p_mem_node->base - 1, 16); | ||
| 2630 | temp_word = (u32)((p_mem_node->base - 1) >> 16); | ||
| 2631 | rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); | ||
| 2632 | |||
| 2633 | return_resource(&(resources->p_mem_head), p_mem_node); | ||
| 2634 | } else { | ||
| 2635 | /* it doesn't need any PMem */ | ||
| 2636 | temp_word = 0x0000; | ||
| 2637 | rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); | ||
| 2638 | |||
| 2639 | return_resource(&(resources->p_mem_head), p_mem_node); | ||
| 2640 | kfree(hold_p_mem_node); | ||
| 2641 | } | ||
| 2642 | } else { | ||
| 2643 | /* it used the most of the range */ | ||
| 2644 | hold_p_mem_node->next = func->p_mem_head; | ||
| 2645 | func->p_mem_head = hold_p_mem_node; | ||
| 2646 | } | ||
| 2647 | } else if (hold_p_mem_node) { | ||
| 2648 | /* it used the whole range */ | ||
| 2649 | hold_p_mem_node->next = func->p_mem_head; | ||
| 2650 | func->p_mem_head = hold_p_mem_node; | ||
| 2651 | } | ||
| 2652 | |||
| 2653 | /* We should be configuring an IRQ and the bridge's base address | ||
| 2654 | * registers if it needs them. Although we have never seen such | ||
| 2655 | * a device | ||
| 2656 | */ | ||
| 2657 | |||
| 2658 | shpchprm_enable_card(ctrl, func, PCI_HEADER_TYPE_BRIDGE); | ||
| 2659 | |||
| 2660 | dbg("PCI Bridge Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, func->device, func->function); | ||
| 2661 | } else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) { | ||
| 2662 | /* Standard device */ | ||
| 2663 | u64 base64; | ||
| 2664 | rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); | ||
| 2665 | |||
| 2666 | if (class_code == PCI_BASE_CLASS_DISPLAY) | ||
| 2667 | return (DEVICE_TYPE_NOT_SUPPORTED); | ||
| 2668 | |||
| 2669 | /* Figure out IO and memory needs */ | ||
| 2670 | for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) { | ||
| 2671 | temp_register = 0xFFFFFFFF; | ||
| 2672 | |||
| 2673 | rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); | ||
| 2674 | rc = pci_bus_read_config_dword(pci_bus, devfn, cloop, &temp_register); | ||
| 2675 | dbg("Bar[%x]=0x%x on bus:dev:func(0x%x:%x:%x)\n", cloop, temp_register, func->bus, func->device, | ||
| 2676 | func->function); | ||
| 2677 | |||
| 2678 | if (!temp_register) | ||
| 2679 | continue; | ||
| 2680 | |||
| 2681 | base64 = 0L; | ||
| 2682 | if (temp_register & PCI_BASE_ADDRESS_SPACE_IO) { | ||
| 2683 | /* Map IO */ | ||
| 2684 | |||
| 2685 | /* set base = amount of IO space */ | ||
| 2686 | base = temp_register & 0xFFFFFFFC; | ||
| 2687 | base = ~base + 1; | ||
| 2688 | |||
| 2689 | dbg("NEED IO length(0x%x)\n", base); | ||
| 2690 | io_node = get_io_resource(&(resources->io_head),(ulong)base); | ||
| 2691 | |||
| 2692 | /* allocate the resource to the board */ | ||
| 2693 | if (io_node) { | ||
| 2694 | dbg("Got IO base=0x%x(length=0x%x)\n", io_node->base, io_node->length); | ||
| 2695 | base = (u32)io_node->base; | ||
| 2696 | io_node->next = func->io_head; | ||
| 2697 | func->io_head = io_node; | ||
| 2698 | } else { | ||
| 2699 | err("Got NO IO resource(length=0x%x)\n", base); | ||
| 2700 | return -ENOMEM; | ||
| 2701 | } | ||
| 2702 | } else { /* map MEM */ | ||
| 2703 | int prefetchable = 1; | ||
| 2704 | struct pci_resource **res_node = &func->p_mem_head; | ||
| 2705 | char *res_type_str = "PMEM"; | ||
| 2706 | u32 temp_register2; | ||
| 2707 | |||
| 2708 | if (!(temp_register & PCI_BASE_ADDRESS_MEM_PREFETCH)) { | ||
| 2709 | prefetchable = 0; | ||
| 2710 | res_node = &func->mem_head; | ||
| 2711 | res_type_str++; | ||
| 2712 | } | ||
| 2713 | |||
| 2714 | base = temp_register & 0xFFFFFFF0; | ||
| 2715 | base = ~base + 1; | ||
| 2716 | |||
| 2717 | switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) { | ||
| 2718 | case PCI_BASE_ADDRESS_MEM_TYPE_32: | ||
| 2719 | dbg("NEED 32 %s bar=0x%x(length=0x%x)\n", res_type_str, temp_register, base); | ||
| 2720 | |||
| 2721 | if (prefetchable && resources->p_mem_head) | ||
| 2722 | mem_node=get_resource(&(resources->p_mem_head), (ulong)base); | ||
| 2723 | else { | ||
| 2724 | if (prefetchable) | ||
| 2725 | dbg("using MEM for PMEM\n"); | ||
| 2726 | mem_node=get_resource(&(resources->mem_head), (ulong)base); | ||
| 2727 | } | ||
| 2728 | |||
| 2729 | /* allocate the resource to the board */ | ||
| 2730 | if (mem_node) { | ||
| 2731 | base = (u32)mem_node->base; | ||
| 2732 | mem_node->next = *res_node; | ||
| 2733 | *res_node = mem_node; | ||
| 2734 | dbg("Got 32 %s base=0x%x(length=0x%x)\n", res_type_str, mem_node->base, | ||
| 2735 | mem_node->length); | ||
| 2736 | } else { | ||
| 2737 | err("Got NO 32 %s resource(length=0x%x)\n", res_type_str, base); | ||
| 2738 | return -ENOMEM; | ||
| 2739 | } | ||
| 2740 | break; | ||
| 2741 | case PCI_BASE_ADDRESS_MEM_TYPE_64: | ||
| 2742 | rc = pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2); | ||
| 2743 | dbg("NEED 64 %s bar=0x%x:%x(length=0x%x)\n", res_type_str, temp_register2, | ||
| 2744 | temp_register, base); | ||
| 2745 | |||
| 2746 | if (prefetchable && resources->p_mem_head) | ||
| 2747 | mem_node = get_resource(&(resources->p_mem_head), (ulong)base); | ||
| 2748 | else { | ||
| 2749 | if (prefetchable) | ||
| 2750 | dbg("using MEM for PMEM\n"); | ||
| 2751 | mem_node = get_resource(&(resources->mem_head), (ulong)base); | ||
| 2752 | } | ||
| 2753 | |||
| 2754 | /* allocate the resource to the board */ | ||
| 2755 | if (mem_node) { | ||
| 2756 | base64 = mem_node->base; | ||
| 2757 | mem_node->next = *res_node; | ||
| 2758 | *res_node = mem_node; | ||
| 2759 | dbg("Got 64 %s base=0x%x:%x(length=%x)\n", res_type_str, (u32)(base64 >> 32), | ||
| 2760 | (u32)base64, mem_node->length); | ||
| 2761 | } else { | ||
| 2762 | err("Got NO 64 %s resource(length=0x%x)\n", res_type_str, base); | ||
| 2763 | return -ENOMEM; | ||
| 2764 | } | ||
| 2765 | break; | ||
| 2766 | default: | ||
| 2767 | dbg("reserved BAR type=0x%x\n", temp_register); | ||
| 2768 | break; | ||
| 2769 | } | ||
| 2770 | |||
| 2771 | } | ||
| 2772 | |||
| 2773 | if (base64) { | ||
| 2774 | rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64); | ||
| 2775 | cloop += 4; | ||
| 2776 | base64 >>= 32; | ||
| 2777 | |||
| 2778 | if (base64) { | ||
| 2779 | dbg("%s: high dword of base64(0x%x) set to 0\n", __FUNCTION__, (u32)base64); | ||
| 2780 | base64 = 0x0L; | ||
| 2781 | } | ||
| 2782 | |||
| 2783 | rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64); | ||
| 2784 | } else { | ||
| 2785 | rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, base); | ||
| 2786 | } | ||
| 2787 | } /* End of base register loop */ | ||
| 2788 | |||
| 2789 | #if defined(CONFIG_X86_64) | ||
| 2790 | /* Figure out which interrupt pin this function uses */ | ||
| 2791 | rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_INTERRUPT_PIN, &temp_byte); | ||
| 2792 | |||
| 2793 | /* If this function needs an interrupt and we are behind a bridge | ||
| 2794 | and the pin is tied to something that's alread mapped, | ||
| 2795 | set this one the same | ||
| 2796 | */ | ||
| 2797 | if (temp_byte && resources->irqs && | ||
| 2798 | (resources->irqs->valid_INT & | ||
| 2799 | (0x01 << ((temp_byte + resources->irqs->barber_pole - 1) & 0x03)))) { | ||
| 2800 | /* We have to share with something already set up */ | ||
| 2801 | IRQ = resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03]; | ||
| 2802 | } else { | ||
| 2803 | /* Program IRQ based on card type */ | ||
| 2804 | rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); | ||
| 2805 | |||
| 2806 | if (class_code == PCI_BASE_CLASS_STORAGE) { | ||
| 2807 | IRQ = shpchp_disk_irq; | ||
| 2808 | } else { | ||
| 2809 | IRQ = shpchp_nic_irq; | ||
| 2810 | } | ||
| 2811 | } | ||
| 2812 | |||
| 2813 | /* IRQ Line */ | ||
| 2814 | rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_INTERRUPT_LINE, IRQ); | ||
| 2815 | |||
| 2816 | if (!behind_bridge) { | ||
| 2817 | rc = shpchp_set_irq(func->bus, func->device, temp_byte + 0x09, IRQ); | ||
| 2818 | if (rc) | ||
| 2819 | return(1); | ||
| 2820 | } else { | ||
| 2821 | /* TBD - this code may also belong in the other clause of this If statement */ | ||
| 2822 | resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03] = IRQ; | ||
| 2823 | resources->irqs->valid_INT |= 0x01 << (temp_byte + resources->irqs->barber_pole - 1) & 0x03; | ||
| 2824 | } | ||
| 2825 | #endif | ||
| 2826 | /* Disable ROM base Address */ | ||
| 2827 | rc = pci_bus_write_config_dword (pci_bus, devfn, PCI_ROM_ADDRESS, 0x00); | ||
| 2828 | |||
| 2829 | /* Set HP parameters (Cache Line Size, Latency Timer) */ | ||
| 2830 | rc = shpchprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_NORMAL); | ||
| 2831 | if (rc) | ||
| 2832 | return rc; | ||
| 2833 | |||
| 2834 | shpchprm_enable_card(ctrl, func, PCI_HEADER_TYPE_NORMAL); | ||
| 2835 | |||
| 2836 | dbg("PCI function Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, func->device, func->function); | ||
| 2837 | } /* End of Not-A-Bridge else */ | ||
| 2838 | else { | ||
| 2839 | /* It's some strange type of PCI adapter (Cardbus?) */ | ||
| 2840 | return(DEVICE_TYPE_NOT_SUPPORTED); | ||
| 2841 | } | ||
| 2842 | |||
| 2843 | func->configured = 1; | ||
| 2844 | |||
| 2845 | return 0; | ||
| 2846 | } | ||
| 2847 | |||
diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c index d867099114ec..89e404805777 100644 --- a/drivers/pci/hotplug/shpchp_pci.c +++ b/drivers/pci/hotplug/shpchp_pci.c | |||
| @@ -37,46 +37,69 @@ | |||
| 37 | #include <linux/pci.h> | 37 | #include <linux/pci.h> |
| 38 | #include "../pci.h" | 38 | #include "../pci.h" |
| 39 | #include "shpchp.h" | 39 | #include "shpchp.h" |
| 40 | #ifndef CONFIG_IA64 | ||
| 41 | #include "../../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependant we are... */ | ||
| 42 | #endif | ||
| 43 | 40 | ||
| 44 | int shpchp_configure_device (struct controller* ctrl, struct pci_func* func) | 41 | int shpchp_configure_device(struct slot *p_slot) |
| 45 | { | 42 | { |
| 46 | unsigned char bus; | 43 | struct pci_dev *dev; |
| 47 | struct pci_bus *child; | 44 | struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; |
| 48 | int num; | 45 | int num, fn; |
| 49 | 46 | ||
| 50 | if (func->pci_dev == NULL) | 47 | dev = pci_find_slot(p_slot->bus, PCI_DEVFN(p_slot->device, 0)); |
| 51 | func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); | 48 | if (dev) { |
| 52 | 49 | err("Device %s already exists at %x:%x, cannot hot-add\n", | |
| 53 | /* Still NULL ? Well then scan for it ! */ | 50 | pci_name(dev), p_slot->bus, p_slot->device); |
| 54 | if (func->pci_dev == NULL) { | 51 | return -EINVAL; |
| 55 | num = pci_scan_slot(ctrl->pci_dev->subordinate, PCI_DEVFN(func->device, func->function)); | ||
| 56 | if (num) { | ||
| 57 | dbg("%s: subordiante %p number %x\n", __FUNCTION__, ctrl->pci_dev->subordinate, | ||
| 58 | ctrl->pci_dev->subordinate->number); | ||
| 59 | pci_bus_add_devices(ctrl->pci_dev->subordinate); | ||
| 60 | } | ||
| 61 | |||
| 62 | func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); | ||
| 63 | if (func->pci_dev == NULL) { | ||
| 64 | dbg("ERROR: pci_dev still null\n"); | ||
| 65 | return 0; | ||
| 66 | } | ||
| 67 | } | 52 | } |
| 68 | 53 | ||
| 69 | if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { | 54 | num = pci_scan_slot(parent, PCI_DEVFN(p_slot->device, 0)); |
| 70 | pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus); | 55 | if (num == 0) { |
| 71 | child = pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus); | 56 | err("No new device found\n"); |
| 72 | pci_do_scan_bus(child); | 57 | return -ENODEV; |
| 58 | } | ||
| 73 | 59 | ||
| 60 | for (fn = 0; fn < 8; fn++) { | ||
| 61 | if (!(dev = pci_find_slot(p_slot->bus, | ||
| 62 | PCI_DEVFN(p_slot->device, fn)))) | ||
| 63 | continue; | ||
| 64 | if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { | ||
| 65 | err("Cannot hot-add display device %s\n", | ||
| 66 | pci_name(dev)); | ||
| 67 | continue; | ||
| 68 | } | ||
| 69 | if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || | ||
| 70 | (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) { | ||
| 71 | /* Find an unused bus number for the new bridge */ | ||
| 72 | struct pci_bus *child; | ||
| 73 | unsigned char busnr, start = parent->secondary; | ||
| 74 | unsigned char end = parent->subordinate; | ||
| 75 | for (busnr = start; busnr <= end; busnr++) { | ||
| 76 | if (!pci_find_bus(pci_domain_nr(parent), | ||
| 77 | busnr)) | ||
| 78 | break; | ||
| 79 | } | ||
| 80 | if (busnr >= end) { | ||
| 81 | err("No free bus for hot-added bridge\n"); | ||
| 82 | continue; | ||
| 83 | } | ||
| 84 | child = pci_add_new_bus(parent, dev, busnr); | ||
| 85 | if (!child) { | ||
| 86 | err("Cannot add new bus for %s\n", | ||
| 87 | pci_name(dev)); | ||
| 88 | continue; | ||
| 89 | } | ||
| 90 | child->subordinate = pci_do_scan_bus(child); | ||
| 91 | pci_bus_size_bridges(child); | ||
| 92 | } | ||
| 93 | /* TBD: program firmware provided _HPP values */ | ||
| 94 | /* program_fw_provided_values(dev); */ | ||
| 74 | } | 95 | } |
| 75 | 96 | ||
| 97 | pci_bus_assign_resources(parent); | ||
| 98 | pci_bus_add_devices(parent); | ||
| 99 | pci_enable_bridges(parent); | ||
| 76 | return 0; | 100 | return 0; |
| 77 | } | 101 | } |
| 78 | 102 | ||
| 79 | |||
| 80 | int shpchp_unconfigure_device(struct pci_func* func) | 103 | int shpchp_unconfigure_device(struct pci_func* func) |
| 81 | { | 104 | { |
| 82 | int rc = 0; | 105 | int rc = 0; |
| @@ -95,44 +118,6 @@ int shpchp_unconfigure_device(struct pci_func* func) | |||
| 95 | return rc; | 118 | return rc; |
| 96 | } | 119 | } |
| 97 | 120 | ||
| 98 | /* | ||
| 99 | * shpchp_set_irq | ||
| 100 | * | ||
| 101 | * @bus_num: bus number of PCI device | ||
| 102 | * @dev_num: device number of PCI device | ||
| 103 | * @slot: pointer to u8 where slot number will be returned | ||
| 104 | */ | ||
| 105 | int shpchp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) | ||
| 106 | { | ||
| 107 | #if defined(CONFIG_X86) && !defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64) | ||
| 108 | int rc; | ||
| 109 | u16 temp_word; | ||
| 110 | struct pci_dev fakedev; | ||
| 111 | struct pci_bus fakebus; | ||
| 112 | |||
| 113 | fakedev.devfn = dev_num << 3; | ||
| 114 | fakedev.bus = &fakebus; | ||
| 115 | fakebus.number = bus_num; | ||
| 116 | dbg("%s: dev %d, bus %d, pin %d, num %d\n", | ||
| 117 | __FUNCTION__, dev_num, bus_num, int_pin, irq_num); | ||
| 118 | rc = pcibios_set_irq_routing(&fakedev, int_pin - 0x0a, irq_num); | ||
| 119 | dbg("%s: rc %d\n", __FUNCTION__, rc); | ||
| 120 | if (!rc) | ||
| 121 | return !rc; | ||
| 122 | |||
| 123 | /* set the Edge Level Control Register (ELCR) */ | ||
| 124 | temp_word = inb(0x4d0); | ||
| 125 | temp_word |= inb(0x4d1) << 8; | ||
| 126 | |||
| 127 | temp_word |= 0x01 << irq_num; | ||
| 128 | |||
| 129 | /* This should only be for x86 as it sets the Edge Level Control Register */ | ||
| 130 | outb((u8) (temp_word & 0xFF), 0x4d0); | ||
| 131 | outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1); | ||
| 132 | #endif | ||
| 133 | return 0; | ||
| 134 | } | ||
| 135 | |||
| 136 | /* More PCI configuration routines; this time centered around hotplug controller */ | 121 | /* More PCI configuration routines; this time centered around hotplug controller */ |
| 137 | 122 | ||
| 138 | 123 | ||
| @@ -447,364 +432,3 @@ int shpchp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot) | |||
| 447 | return 0; | 432 | return 0; |
| 448 | } | 433 | } |
| 449 | 434 | ||
| 450 | |||
| 451 | /* | ||
| 452 | * shpchp_save_used_resources | ||
| 453 | * | ||
| 454 | * Stores used resource information for existing boards. this is | ||
| 455 | * for boards that were in the system when this driver was loaded. | ||
| 456 | * this function is for hot plug ADD | ||
| 457 | * | ||
| 458 | * returns 0 if success | ||
| 459 | * if disable == 1(DISABLE_CARD), | ||
| 460 | * it loops for all functions of the slot and disables them. | ||
| 461 | * else, it just get resources of the function and return. | ||
| 462 | */ | ||
| 463 | int shpchp_save_used_resources(struct controller *ctrl, struct pci_func *func, int disable) | ||
| 464 | { | ||
| 465 | u8 cloop; | ||
| 466 | u8 header_type; | ||
| 467 | u8 secondary_bus; | ||
| 468 | u8 temp_byte; | ||
| 469 | u16 command; | ||
| 470 | u16 save_command; | ||
| 471 | u16 w_base, w_length; | ||
| 472 | u32 temp_register; | ||
| 473 | u32 save_base; | ||
| 474 | u32 base, length; | ||
| 475 | u64 base64 = 0; | ||
| 476 | int index = 0; | ||
| 477 | unsigned int devfn; | ||
| 478 | struct pci_resource *mem_node = NULL; | ||
| 479 | struct pci_resource *p_mem_node = NULL; | ||
| 480 | struct pci_resource *t_mem_node; | ||
| 481 | struct pci_resource *io_node; | ||
| 482 | struct pci_resource *bus_node; | ||
| 483 | struct pci_bus lpci_bus, *pci_bus; | ||
| 484 | memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); | ||
| 485 | pci_bus = &lpci_bus; | ||
| 486 | |||
| 487 | if (disable) | ||
| 488 | func = shpchp_slot_find(func->bus, func->device, index++); | ||
| 489 | |||
| 490 | while ((func != NULL) && func->is_a_board) { | ||
| 491 | pci_bus->number = func->bus; | ||
| 492 | devfn = PCI_DEVFN(func->device, func->function); | ||
| 493 | |||
| 494 | /* Save the command register */ | ||
| 495 | pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &save_command); | ||
| 496 | |||
| 497 | if (disable) { | ||
| 498 | /* disable card */ | ||
| 499 | command = 0x00; | ||
| 500 | pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); | ||
| 501 | } | ||
| 502 | |||
| 503 | /* Check for Bridge */ | ||
| 504 | pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type); | ||
| 505 | |||
| 506 | if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */ | ||
| 507 | dbg("Save_used_res of PCI bridge b:d=0x%x:%x, sc=0x%x\n", | ||
| 508 | func->bus, func->device, save_command); | ||
| 509 | if (disable) { | ||
| 510 | /* Clear Bridge Control Register */ | ||
| 511 | command = 0x00; | ||
| 512 | pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command); | ||
| 513 | } | ||
| 514 | |||
| 515 | pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); | ||
| 516 | pci_bus_read_config_byte(pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte); | ||
| 517 | |||
| 518 | bus_node = kmalloc(sizeof(struct pci_resource), | ||
| 519 | GFP_KERNEL); | ||
| 520 | if (!bus_node) | ||
| 521 | return -ENOMEM; | ||
| 522 | |||
| 523 | bus_node->base = (ulong)secondary_bus; | ||
| 524 | bus_node->length = (ulong)(temp_byte - secondary_bus + 1); | ||
| 525 | |||
| 526 | bus_node->next = func->bus_head; | ||
| 527 | func->bus_head = bus_node; | ||
| 528 | |||
| 529 | /* Save IO base and Limit registers */ | ||
| 530 | pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_BASE, &temp_byte); | ||
| 531 | base = temp_byte; | ||
| 532 | pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_LIMIT, &temp_byte); | ||
| 533 | length = temp_byte; | ||
| 534 | |||
| 535 | if ((base <= length) && (!disable || (save_command & PCI_COMMAND_IO))) { | ||
| 536 | io_node = kmalloc(sizeof(struct pci_resource), | ||
| 537 | GFP_KERNEL); | ||
| 538 | if (!io_node) | ||
| 539 | return -ENOMEM; | ||
| 540 | |||
| 541 | io_node->base = (ulong)(base & PCI_IO_RANGE_MASK) << 8; | ||
| 542 | io_node->length = (ulong)(length - base + 0x10) << 8; | ||
| 543 | |||
| 544 | io_node->next = func->io_head; | ||
| 545 | func->io_head = io_node; | ||
| 546 | } | ||
| 547 | |||
| 548 | /* Save memory base and Limit registers */ | ||
| 549 | pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_BASE, &w_base); | ||
| 550 | pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length); | ||
| 551 | |||
| 552 | if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) { | ||
| 553 | mem_node = kmalloc(sizeof(struct pci_resource), | ||
| 554 | GFP_KERNEL); | ||
| 555 | if (!mem_node) | ||
| 556 | return -ENOMEM; | ||
| 557 | |||
| 558 | mem_node->base = (ulong)w_base << 16; | ||
| 559 | mem_node->length = (ulong)(w_length - w_base + 0x10) << 16; | ||
| 560 | |||
| 561 | mem_node->next = func->mem_head; | ||
| 562 | func->mem_head = mem_node; | ||
| 563 | } | ||
| 564 | /* Save prefetchable memory base and Limit registers */ | ||
| 565 | pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base); | ||
| 566 | pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length); | ||
| 567 | |||
| 568 | if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) { | ||
| 569 | p_mem_node = kmalloc(sizeof(struct pci_resource), | ||
| 570 | GFP_KERNEL); | ||
| 571 | if (!p_mem_node) | ||
| 572 | return -ENOMEM; | ||
| 573 | |||
| 574 | p_mem_node->base = (ulong)w_base << 16; | ||
| 575 | p_mem_node->length = (ulong)(w_length - w_base + 0x10) << 16; | ||
| 576 | |||
| 577 | p_mem_node->next = func->p_mem_head; | ||
| 578 | func->p_mem_head = p_mem_node; | ||
| 579 | } | ||
| 580 | } else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) { | ||
| 581 | dbg("Save_used_res of PCI adapter b:d=0x%x:%x, sc=0x%x\n", | ||
| 582 | func->bus, func->device, save_command); | ||
| 583 | |||
| 584 | /* Figure out IO and memory base lengths */ | ||
| 585 | for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) { | ||
| 586 | pci_bus_read_config_dword(pci_bus, devfn, cloop, &save_base); | ||
| 587 | |||
| 588 | temp_register = 0xFFFFFFFF; | ||
| 589 | pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register); | ||
| 590 | pci_bus_read_config_dword(pci_bus, devfn, cloop, &temp_register); | ||
| 591 | |||
| 592 | if (!disable) | ||
| 593 | pci_bus_write_config_dword(pci_bus, devfn, cloop, save_base); | ||
| 594 | |||
| 595 | if (!temp_register) | ||
| 596 | continue; | ||
| 597 | |||
| 598 | base = temp_register; | ||
| 599 | |||
| 600 | if ((base & PCI_BASE_ADDRESS_SPACE_IO) && | ||
| 601 | (!disable || (save_command & PCI_COMMAND_IO))) { | ||
| 602 | /* IO base */ | ||
| 603 | /* set temp_register = amount of IO space requested */ | ||
| 604 | base = base & 0xFFFFFFFCL; | ||
| 605 | base = (~base) + 1; | ||
| 606 | |||
| 607 | io_node = kmalloc(sizeof (struct pci_resource), | ||
| 608 | GFP_KERNEL); | ||
| 609 | if (!io_node) | ||
| 610 | return -ENOMEM; | ||
| 611 | |||
| 612 | io_node->base = (ulong)save_base & PCI_BASE_ADDRESS_IO_MASK; | ||
| 613 | io_node->length = (ulong)base; | ||
| 614 | dbg("sur adapter: IO bar=0x%x(length=0x%x)\n", | ||
| 615 | io_node->base, io_node->length); | ||
| 616 | |||
| 617 | io_node->next = func->io_head; | ||
| 618 | func->io_head = io_node; | ||
| 619 | } else { /* map Memory */ | ||
| 620 | int prefetchable = 1; | ||
| 621 | /* struct pci_resources **res_node; */ | ||
| 622 | char *res_type_str = "PMEM"; | ||
| 623 | u32 temp_register2; | ||
| 624 | |||
| 625 | t_mem_node = kmalloc(sizeof (struct pci_resource), | ||
| 626 | GFP_KERNEL); | ||
| 627 | if (!t_mem_node) | ||
| 628 | return -ENOMEM; | ||
| 629 | |||
| 630 | if (!(base & PCI_BASE_ADDRESS_MEM_PREFETCH) && | ||
| 631 | (!disable || (save_command & PCI_COMMAND_MEMORY))) { | ||
| 632 | prefetchable = 0; | ||
| 633 | mem_node = t_mem_node; | ||
| 634 | res_type_str++; | ||
| 635 | } else | ||
| 636 | p_mem_node = t_mem_node; | ||
| 637 | |||
| 638 | base = base & 0xFFFFFFF0L; | ||
| 639 | base = (~base) + 1; | ||
| 640 | |||
| 641 | switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) { | ||
| 642 | case PCI_BASE_ADDRESS_MEM_TYPE_32: | ||
| 643 | if (prefetchable) { | ||
| 644 | p_mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK; | ||
| 645 | p_mem_node->length = (ulong)base; | ||
| 646 | dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n", | ||
| 647 | res_type_str, | ||
| 648 | p_mem_node->base, | ||
| 649 | p_mem_node->length); | ||
| 650 | |||
| 651 | p_mem_node->next = func->p_mem_head; | ||
| 652 | func->p_mem_head = p_mem_node; | ||
| 653 | } else { | ||
| 654 | mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK; | ||
| 655 | mem_node->length = (ulong)base; | ||
| 656 | dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n", | ||
| 657 | res_type_str, | ||
| 658 | mem_node->base, | ||
| 659 | mem_node->length); | ||
| 660 | |||
| 661 | mem_node->next = func->mem_head; | ||
| 662 | func->mem_head = mem_node; | ||
| 663 | } | ||
| 664 | break; | ||
| 665 | case PCI_BASE_ADDRESS_MEM_TYPE_64: | ||
| 666 | pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2); | ||
| 667 | base64 = temp_register2; | ||
| 668 | base64 = (base64 << 32) | save_base; | ||
| 669 | |||
| 670 | if (temp_register2) { | ||
| 671 | dbg("sur adapter: 64 %s high dword of base64(0x%x:%x) masked to 0\n", | ||
| 672 | res_type_str, temp_register2, (u32)base64); | ||
| 673 | base64 &= 0x00000000FFFFFFFFL; | ||
| 674 | } | ||
| 675 | |||
| 676 | if (prefetchable) { | ||
| 677 | p_mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK; | ||
| 678 | p_mem_node->length = base; | ||
| 679 | dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n", | ||
| 680 | res_type_str, | ||
| 681 | p_mem_node->base, | ||
| 682 | p_mem_node->length); | ||
| 683 | |||
| 684 | p_mem_node->next = func->p_mem_head; | ||
| 685 | func->p_mem_head = p_mem_node; | ||
| 686 | } else { | ||
| 687 | mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK; | ||
| 688 | mem_node->length = base; | ||
| 689 | dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n", | ||
| 690 | res_type_str, | ||
| 691 | mem_node->base, | ||
| 692 | mem_node->length); | ||
| 693 | |||
| 694 | mem_node->next = func->mem_head; | ||
| 695 | func->mem_head = mem_node; | ||
| 696 | } | ||
| 697 | cloop += 4; | ||
| 698 | break; | ||
| 699 | default: | ||
| 700 | dbg("asur: reserved BAR type=0x%x\n", | ||
| 701 | temp_register); | ||
| 702 | break; | ||
| 703 | } | ||
| 704 | } | ||
| 705 | } /* End of base register loop */ | ||
| 706 | } else { /* Some other unknown header type */ | ||
| 707 | dbg("Save_used_res of PCI unknown type b:d=0x%x:%x. skip.\n", | ||
| 708 | func->bus, func->device); | ||
| 709 | } | ||
| 710 | |||
| 711 | /* find the next device in this slot */ | ||
| 712 | if (!disable) | ||
| 713 | break; | ||
| 714 | func = shpchp_slot_find(func->bus, func->device, index++); | ||
| 715 | } | ||
| 716 | |||
| 717 | return 0; | ||
| 718 | } | ||
| 719 | |||
| 720 | /** | ||
| 721 | * kfree_resource_list: release memory of all list members | ||
| 722 | * @res: resource list to free | ||
| 723 | */ | ||
| 724 | static inline void | ||
| 725 | return_resource_list(struct pci_resource **func, struct pci_resource **res) | ||
| 726 | { | ||
| 727 | struct pci_resource *node; | ||
| 728 | struct pci_resource *t_node; | ||
| 729 | |||
| 730 | node = *func; | ||
| 731 | *func = NULL; | ||
| 732 | while (node) { | ||
| 733 | t_node = node->next; | ||
| 734 | return_resource(res, node); | ||
| 735 | node = t_node; | ||
| 736 | } | ||
| 737 | } | ||
| 738 | |||
| 739 | /* | ||
| 740 | * shpchp_return_board_resources | ||
| 741 | * | ||
| 742 | * this routine returns all resources allocated to a board to | ||
| 743 | * the available pool. | ||
| 744 | * | ||
| 745 | * returns 0 if success | ||
| 746 | */ | ||
| 747 | int shpchp_return_board_resources(struct pci_func * func, | ||
| 748 | struct resource_lists * resources) | ||
| 749 | { | ||
| 750 | int rc; | ||
| 751 | dbg("%s\n", __FUNCTION__); | ||
| 752 | |||
| 753 | if (!func) | ||
| 754 | return 1; | ||
| 755 | |||
| 756 | return_resource_list(&(func->io_head),&(resources->io_head)); | ||
| 757 | return_resource_list(&(func->mem_head),&(resources->mem_head)); | ||
| 758 | return_resource_list(&(func->p_mem_head),&(resources->p_mem_head)); | ||
| 759 | return_resource_list(&(func->bus_head),&(resources->bus_head)); | ||
| 760 | |||
| 761 | rc = shpchp_resource_sort_and_combine(&(resources->mem_head)); | ||
| 762 | rc |= shpchp_resource_sort_and_combine(&(resources->p_mem_head)); | ||
| 763 | rc |= shpchp_resource_sort_and_combine(&(resources->io_head)); | ||
| 764 | rc |= shpchp_resource_sort_and_combine(&(resources->bus_head)); | ||
| 765 | |||
| 766 | return rc; | ||
| 767 | } | ||
| 768 | |||
| 769 | /** | ||
| 770 | * kfree_resource_list: release memory of all list members | ||
| 771 | * @res: resource list to free | ||
| 772 | */ | ||
| 773 | static inline void | ||
| 774 | kfree_resource_list(struct pci_resource **r) | ||
| 775 | { | ||
| 776 | struct pci_resource *res, *tres; | ||
| 777 | |||
| 778 | res = *r; | ||
| 779 | *r = NULL; | ||
| 780 | |||
| 781 | while (res) { | ||
| 782 | tres = res; | ||
| 783 | res = res->next; | ||
| 784 | kfree(tres); | ||
| 785 | } | ||
| 786 | } | ||
| 787 | |||
| 788 | /** | ||
| 789 | * shpchp_destroy_resource_list: put node back in the resource list | ||
| 790 | * @resources: list to put nodes back | ||
| 791 | */ | ||
| 792 | void shpchp_destroy_resource_list(struct resource_lists *resources) | ||
| 793 | { | ||
| 794 | kfree_resource_list(&(resources->io_head)); | ||
| 795 | kfree_resource_list(&(resources->mem_head)); | ||
| 796 | kfree_resource_list(&(resources->p_mem_head)); | ||
| 797 | kfree_resource_list(&(resources->bus_head)); | ||
| 798 | } | ||
| 799 | |||
| 800 | /** | ||
| 801 | * shpchp_destroy_board_resources: put node back in the resource list | ||
| 802 | * @resources: list to put nodes back | ||
| 803 | */ | ||
| 804 | void shpchp_destroy_board_resources(struct pci_func * func) | ||
| 805 | { | ||
| 806 | kfree_resource_list(&(func->io_head)); | ||
| 807 | kfree_resource_list(&(func->mem_head)); | ||
| 808 | kfree_resource_list(&(func->p_mem_head)); | ||
| 809 | kfree_resource_list(&(func->bus_head)); | ||
| 810 | } | ||
diff --git a/drivers/pci/hotplug/shpchp_sysfs.c b/drivers/pci/hotplug/shpchp_sysfs.c index c9445ebda5c7..b0e781dbcffb 100644 --- a/drivers/pci/hotplug/shpchp_sysfs.c +++ b/drivers/pci/hotplug/shpchp_sysfs.c | |||
| @@ -40,43 +40,49 @@ | |||
| 40 | 40 | ||
| 41 | static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, char *buf) | 41 | static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, char *buf) |
| 42 | { | 42 | { |
| 43 | struct pci_dev *pci_dev; | 43 | struct pci_dev *pdev; |
| 44 | struct controller *ctrl; | ||
| 45 | char * out = buf; | 44 | char * out = buf; |
| 46 | int index; | 45 | int index, busnr; |
| 47 | struct pci_resource *res; | 46 | struct resource *res; |
| 47 | struct pci_bus *bus; | ||
| 48 | 48 | ||
| 49 | pci_dev = container_of (dev, struct pci_dev, dev); | 49 | pdev = container_of (dev, struct pci_dev, dev); |
| 50 | ctrl = pci_get_drvdata(pci_dev); | 50 | bus = pdev->subordinate; |
| 51 | 51 | ||
| 52 | out += sprintf(buf, "Free resources: memory\n"); | 52 | out += sprintf(buf, "Free resources: memory\n"); |
| 53 | index = 11; | 53 | for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) { |
| 54 | res = ctrl->mem_head; | 54 | res = bus->resource[index]; |
| 55 | while (res && index--) { | 55 | if (res && (res->flags & IORESOURCE_MEM) && |
| 56 | out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); | 56 | !(res->flags & IORESOURCE_PREFETCH)) { |
| 57 | res = res->next; | 57 | out += sprintf(out, "start = %8.8lx, length = %8.8lx\n", |
| 58 | res->start, (res->end - res->start)); | ||
| 59 | } | ||
| 58 | } | 60 | } |
| 59 | out += sprintf(out, "Free resources: prefetchable memory\n"); | 61 | out += sprintf(out, "Free resources: prefetchable memory\n"); |
| 60 | index = 11; | 62 | for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) { |
| 61 | res = ctrl->p_mem_head; | 63 | res = bus->resource[index]; |
| 62 | while (res && index--) { | 64 | if (res && (res->flags & IORESOURCE_MEM) && |
| 63 | out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); | 65 | (res->flags & IORESOURCE_PREFETCH)) { |
| 64 | res = res->next; | 66 | out += sprintf(out, "start = %8.8lx, length = %8.8lx\n", |
| 67 | res->start, (res->end - res->start)); | ||
| 68 | } | ||
| 65 | } | 69 | } |
| 66 | out += sprintf(out, "Free resources: IO\n"); | 70 | out += sprintf(out, "Free resources: IO\n"); |
| 67 | index = 11; | 71 | for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) { |
| 68 | res = ctrl->io_head; | 72 | res = bus->resource[index]; |
| 69 | while (res && index--) { | 73 | if (res && (res->flags & IORESOURCE_IO)) { |
| 70 | out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); | 74 | out += sprintf(out, "start = %8.8lx, length = %8.8lx\n", |
| 71 | res = res->next; | 75 | res->start, (res->end - res->start)); |
| 76 | } | ||
| 72 | } | 77 | } |
| 73 | out += sprintf(out, "Free resources: bus numbers\n"); | 78 | out += sprintf(out, "Free resources: bus numbers\n"); |
| 74 | index = 11; | 79 | for (busnr = bus->secondary; busnr <= bus->subordinate; busnr++) { |
| 75 | res = ctrl->bus_head; | 80 | if (!pci_find_bus(pci_domain_nr(bus), busnr)) |
| 76 | while (res && index--) { | 81 | break; |
| 77 | out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); | ||
| 78 | res = res->next; | ||
| 79 | } | 82 | } |
| 83 | if (busnr < bus->subordinate) | ||
| 84 | out += sprintf(out, "start = %8.8x, length = %8.8x\n", | ||
| 85 | busnr, (bus->subordinate - busnr)); | ||
| 80 | 86 | ||
| 81 | return out - buf; | 87 | return out - buf; |
| 82 | } | 88 | } |
| @@ -84,16 +90,16 @@ static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL); | |||
| 84 | 90 | ||
| 85 | static ssize_t show_dev (struct device *dev, struct device_attribute *attr, char *buf) | 91 | static ssize_t show_dev (struct device *dev, struct device_attribute *attr, char *buf) |
| 86 | { | 92 | { |
| 87 | struct pci_dev *pci_dev; | 93 | struct pci_dev *pdev, *fdev; |
| 88 | struct controller *ctrl; | 94 | struct controller *ctrl; |
| 89 | char * out = buf; | 95 | char * out = buf; |
| 90 | int index; | 96 | int index; |
| 91 | struct pci_resource *res; | 97 | struct resource *res; |
| 92 | struct pci_func *new_slot; | 98 | struct pci_func *new_slot; |
| 93 | struct slot *slot; | 99 | struct slot *slot; |
| 94 | 100 | ||
| 95 | pci_dev = container_of (dev, struct pci_dev, dev); | 101 | pdev = container_of (dev, struct pci_dev, dev); |
| 96 | ctrl = pci_get_drvdata(pci_dev); | 102 | ctrl = pci_get_drvdata(pdev); |
| 97 | 103 | ||
| 98 | slot=ctrl->slot; | 104 | slot=ctrl->slot; |
| 99 | 105 | ||
| @@ -101,34 +107,47 @@ static ssize_t show_dev (struct device *dev, struct device_attribute *attr, char | |||
| 101 | new_slot = shpchp_slot_find(slot->bus, slot->device, 0); | 107 | new_slot = shpchp_slot_find(slot->bus, slot->device, 0); |
| 102 | if (!new_slot) | 108 | if (!new_slot) |
| 103 | break; | 109 | break; |
| 110 | fdev = new_slot->pci_dev; | ||
| 111 | if (!fdev) | ||
| 112 | break; | ||
| 104 | out += sprintf(out, "assigned resources: memory\n"); | 113 | out += sprintf(out, "assigned resources: memory\n"); |
| 105 | index = 11; | 114 | for (index=0; index <= PCI_NUM_RESOURCES; index++) { |
| 106 | res = new_slot->mem_head; | 115 | res = &(fdev->resource[index]); |
| 107 | while (res && index--) { | 116 | if (res && (res->flags & IORESOURCE_MEM) && |
| 108 | out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); | 117 | !(res->flags & IORESOURCE_PREFETCH)) { |
| 109 | res = res->next; | 118 | out += sprintf(out, |
| 119 | "start = %8.8lx, length = %8.8lx\n", | ||
| 120 | res->start, (res->end - res->start)); | ||
| 121 | } | ||
| 110 | } | 122 | } |
| 111 | out += sprintf(out, "assigned resources: prefetchable memory\n"); | 123 | out += sprintf(out, "assigned resources: prefetchable memory\n"); |
| 112 | index = 11; | 124 | for (index=0; index <= PCI_NUM_RESOURCES; index++) { |
| 113 | res = new_slot->p_mem_head; | 125 | res = &(fdev->resource[index]); |
| 114 | while (res && index--) { | 126 | if (res && (res->flags & (IORESOURCE_MEM | |
| 115 | out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); | 127 | IORESOURCE_PREFETCH))) { |
| 116 | res = res->next; | 128 | out += sprintf(out, |
| 129 | "start = %8.8lx, length = %8.8lx\n", | ||
| 130 | res->start, (res->end - res->start)); | ||
| 131 | } | ||
| 117 | } | 132 | } |
| 118 | out += sprintf(out, "assigned resources: IO\n"); | 133 | out += sprintf(out, "assigned resources: IO\n"); |
| 119 | index = 11; | 134 | for (index=0; index <= PCI_NUM_RESOURCES; index++) { |
| 120 | res = new_slot->io_head; | 135 | res = &(fdev->resource[index]); |
| 121 | while (res && index--) { | 136 | if (res && (res->flags & IORESOURCE_IO)) { |
| 122 | out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); | 137 | out += sprintf(out, |
| 123 | res = res->next; | 138 | "start = %8.8lx, length = %8.8lx\n", |
| 139 | res->start, (res->end - res->start)); | ||
| 140 | } | ||
| 124 | } | 141 | } |
| 125 | out += sprintf(out, "assigned resources: bus numbers\n"); | 142 | out += sprintf(out, "assigned resources: bus numbers\n"); |
| 126 | index = 11; | 143 | if (fdev->subordinate) |
| 127 | res = new_slot->bus_head; | 144 | out += sprintf(out, "start = %8.8x, length = %8.8x\n", |
| 128 | while (res && index--) { | 145 | fdev->subordinate->secondary, |
| 129 | out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); | 146 | (fdev->subordinate->subordinate - |
| 130 | res = res->next; | 147 | fdev->subordinate->secondary)); |
| 131 | } | 148 | else |
| 149 | out += sprintf(out, "start = %8.8x, length = %8.8x\n", | ||
| 150 | fdev->bus->number, 1); | ||
| 132 | slot=slot->next; | 151 | slot=slot->next; |
| 133 | } | 152 | } |
| 134 | 153 | ||
diff --git a/drivers/pci/hotplug/shpchprm.h b/drivers/pci/hotplug/shpchprm.h index 057b192ce589..df474b27d6e8 100644 --- a/drivers/pci/hotplug/shpchprm.h +++ b/drivers/pci/hotplug/shpchprm.h | |||
| @@ -32,24 +32,12 @@ | |||
| 32 | 32 | ||
| 33 | #ifdef CONFIG_HOTPLUG_PCI_SHPC_PHPRM_LEGACY | 33 | #ifdef CONFIG_HOTPLUG_PCI_SHPC_PHPRM_LEGACY |
| 34 | #include "shpchprm_legacy.h" | 34 | #include "shpchprm_legacy.h" |
| 35 | #else | ||
| 36 | #include "shpchprm_nonacpi.h" | ||
| 37 | #endif | 35 | #endif |
| 38 | 36 | ||
| 39 | int shpchprm_init(enum php_ctlr_type ct); | 37 | int shpchprm_init(enum php_ctlr_type ct); |
| 40 | void shpchprm_cleanup(void); | 38 | void shpchprm_cleanup(void); |
| 41 | int shpchprm_print_pirt(void); | ||
| 42 | int shpchprm_find_available_resources(struct controller *ctrl); | ||
| 43 | int shpchprm_set_hpp(struct controller *ctrl, struct pci_func *func, u8 card_type); | 39 | int shpchprm_set_hpp(struct controller *ctrl, struct pci_func *func, u8 card_type); |
| 44 | void shpchprm_enable_card(struct controller *ctrl, struct pci_func *func, u8 card_type); | 40 | void shpchprm_enable_card(struct controller *ctrl, struct pci_func *func, u8 card_type); |
| 45 | int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum); | 41 | int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum); |
| 46 | 42 | ||
| 47 | #ifdef DEBUG | ||
| 48 | #define RES_CHECK(this, bits) \ | ||
| 49 | { if (((this) & (bits - 1))) \ | ||
| 50 | printk("%s:%d ERR: potential res loss!\n", __FUNCTION__, __LINE__); } | ||
| 51 | #else | ||
| 52 | #define RES_CHECK(this, bits) | ||
| 53 | #endif | ||
| 54 | |||
| 55 | #endif /* _SHPCHPRM_H_ */ | 43 | #endif /* _SHPCHPRM_H_ */ |
diff --git a/drivers/pci/hotplug/shpchprm_acpi.c b/drivers/pci/hotplug/shpchprm_acpi.c index d37b31658edf..3d2f9c5269c7 100644 --- a/drivers/pci/hotplug/shpchprm_acpi.c +++ b/drivers/pci/hotplug/shpchprm_acpi.c | |||
| @@ -34,9 +34,6 @@ | |||
| 34 | #include <linux/efi.h> | 34 | #include <linux/efi.h> |
| 35 | #include <asm/uaccess.h> | 35 | #include <asm/uaccess.h> |
| 36 | #include <asm/system.h> | 36 | #include <asm/system.h> |
| 37 | #ifdef CONFIG_IA64 | ||
| 38 | #include <asm/iosapic.h> | ||
| 39 | #endif | ||
| 40 | #include <acpi/acpi.h> | 37 | #include <acpi/acpi.h> |
| 41 | #include <acpi/acpi_bus.h> | 38 | #include <acpi/acpi_bus.h> |
| 42 | #include <acpi/actypes.h> | 39 | #include <acpi/actypes.h> |
| @@ -75,10 +72,6 @@ struct acpi_php_slot { | |||
| 75 | int dev; | 72 | int dev; |
| 76 | int fun; | 73 | int fun; |
| 77 | u32 sun; | 74 | u32 sun; |
| 78 | struct pci_resource *mem_head; | ||
| 79 | struct pci_resource *p_mem_head; | ||
| 80 | struct pci_resource *io_head; | ||
| 81 | struct pci_resource *bus_head; | ||
| 82 | void *slot_ops; /* _STA, _EJx, etc */ | 75 | void *slot_ops; /* _STA, _EJx, etc */ |
| 83 | struct slot *slot; | 76 | struct slot *slot; |
| 84 | }; /* per func */ | 77 | }; /* per func */ |
| @@ -95,14 +88,6 @@ struct acpi_bridge { | |||
| 95 | int bus; /* pdev->subordinate->number */ | 88 | int bus; /* pdev->subordinate->number */ |
| 96 | struct acpi__hpp *_hpp; | 89 | struct acpi__hpp *_hpp; |
| 97 | struct acpi_php_slot *slots; | 90 | struct acpi_php_slot *slots; |
| 98 | struct pci_resource *tmem_head; /* total from crs */ | ||
| 99 | struct pci_resource *tp_mem_head; /* total from crs */ | ||
| 100 | struct pci_resource *tio_head; /* total from crs */ | ||
| 101 | struct pci_resource *tbus_head; /* total from crs */ | ||
| 102 | struct pci_resource *mem_head; /* available */ | ||
| 103 | struct pci_resource *p_mem_head; /* available */ | ||
| 104 | struct pci_resource *io_head; /* available */ | ||
| 105 | struct pci_resource *bus_head; /* available */ | ||
| 106 | int scanned; | 91 | int scanned; |
| 107 | int type; | 92 | int type; |
| 108 | }; | 93 | }; |
| @@ -252,485 +237,6 @@ static void acpi_run_oshp ( struct acpi_bridge *ab) | |||
| 252 | return; | 237 | return; |
| 253 | } | 238 | } |
| 254 | 239 | ||
| 255 | static acpi_status acpi_evaluate_crs( | ||
| 256 | acpi_handle handle, | ||
| 257 | struct acpi_resource **retbuf | ||
| 258 | ) | ||
| 259 | { | ||
| 260 | acpi_status status; | ||
| 261 | struct acpi_buffer crsbuf; | ||
| 262 | u8 *path_name = acpi_path_name(handle); | ||
| 263 | |||
| 264 | crsbuf.length = 0; | ||
| 265 | crsbuf.pointer = NULL; | ||
| 266 | |||
| 267 | status = acpi_get_current_resources (handle, &crsbuf); | ||
| 268 | |||
| 269 | switch (status) { | ||
| 270 | case AE_BUFFER_OVERFLOW: | ||
| 271 | break; /* found */ | ||
| 272 | case AE_NOT_FOUND: | ||
| 273 | dbg("acpi_shpchprm:%s _CRS not found\n", path_name); | ||
| 274 | return status; | ||
| 275 | default: | ||
| 276 | err ("acpi_shpchprm:%s _CRS fail=0x%x\n", path_name, status); | ||
| 277 | return status; | ||
| 278 | } | ||
| 279 | |||
| 280 | crsbuf.pointer = kmalloc (crsbuf.length, GFP_KERNEL); | ||
| 281 | if (!crsbuf.pointer) { | ||
| 282 | err ("acpi_shpchprm: alloc %ld bytes for %s _CRS fail\n", (ulong)crsbuf.length, path_name); | ||
| 283 | return AE_NO_MEMORY; | ||
| 284 | } | ||
| 285 | |||
| 286 | status = acpi_get_current_resources (handle, &crsbuf); | ||
| 287 | if (ACPI_FAILURE(status)) { | ||
| 288 | err("acpi_shpchprm: %s _CRS fail=0x%x.\n", path_name, status); | ||
| 289 | kfree(crsbuf.pointer); | ||
| 290 | return status; | ||
| 291 | } | ||
| 292 | |||
| 293 | *retbuf = crsbuf.pointer; | ||
| 294 | |||
| 295 | return status; | ||
| 296 | } | ||
| 297 | |||
| 298 | static void free_pci_resource ( struct pci_resource *aprh) | ||
| 299 | { | ||
| 300 | struct pci_resource *res, *next; | ||
| 301 | |||
| 302 | for (res = aprh; res; res = next) { | ||
| 303 | next = res->next; | ||
| 304 | kfree(res); | ||
| 305 | } | ||
| 306 | } | ||
| 307 | |||
| 308 | static void print_pci_resource ( struct pci_resource *aprh) | ||
| 309 | { | ||
| 310 | struct pci_resource *res; | ||
| 311 | |||
| 312 | for (res = aprh; res; res = res->next) | ||
| 313 | dbg(" base= 0x%x length= 0x%x\n", res->base, res->length); | ||
| 314 | } | ||
| 315 | |||
| 316 | static void print_slot_resources( struct acpi_php_slot *aps) | ||
| 317 | { | ||
| 318 | if (aps->bus_head) { | ||
| 319 | dbg(" BUS Resources:\n"); | ||
| 320 | print_pci_resource (aps->bus_head); | ||
| 321 | } | ||
| 322 | |||
| 323 | if (aps->io_head) { | ||
| 324 | dbg(" IO Resources:\n"); | ||
| 325 | print_pci_resource (aps->io_head); | ||
| 326 | } | ||
| 327 | |||
| 328 | if (aps->mem_head) { | ||
| 329 | dbg(" MEM Resources:\n"); | ||
| 330 | print_pci_resource (aps->mem_head); | ||
| 331 | } | ||
| 332 | |||
| 333 | if (aps->p_mem_head) { | ||
| 334 | dbg(" PMEM Resources:\n"); | ||
| 335 | print_pci_resource (aps->p_mem_head); | ||
| 336 | } | ||
| 337 | } | ||
| 338 | |||
| 339 | static void print_pci_resources( struct acpi_bridge *ab) | ||
| 340 | { | ||
| 341 | if (ab->tbus_head) { | ||
| 342 | dbg(" Total BUS Resources:\n"); | ||
| 343 | print_pci_resource (ab->tbus_head); | ||
| 344 | } | ||
| 345 | if (ab->bus_head) { | ||
| 346 | dbg(" BUS Resources:\n"); | ||
| 347 | print_pci_resource (ab->bus_head); | ||
| 348 | } | ||
| 349 | |||
| 350 | if (ab->tio_head) { | ||
| 351 | dbg(" Total IO Resources:\n"); | ||
| 352 | print_pci_resource (ab->tio_head); | ||
| 353 | } | ||
| 354 | if (ab->io_head) { | ||
| 355 | dbg(" IO Resources:\n"); | ||
| 356 | print_pci_resource (ab->io_head); | ||
| 357 | } | ||
| 358 | |||
| 359 | if (ab->tmem_head) { | ||
| 360 | dbg(" Total MEM Resources:\n"); | ||
| 361 | print_pci_resource (ab->tmem_head); | ||
| 362 | } | ||
| 363 | if (ab->mem_head) { | ||
| 364 | dbg(" MEM Resources:\n"); | ||
| 365 | print_pci_resource (ab->mem_head); | ||
| 366 | } | ||
| 367 | |||
| 368 | if (ab->tp_mem_head) { | ||
| 369 | dbg(" Total PMEM Resources:\n"); | ||
| 370 | print_pci_resource (ab->tp_mem_head); | ||
| 371 | } | ||
| 372 | if (ab->p_mem_head) { | ||
| 373 | dbg(" PMEM Resources:\n"); | ||
| 374 | print_pci_resource (ab->p_mem_head); | ||
| 375 | } | ||
| 376 | if (ab->_hpp) { | ||
| 377 | dbg(" _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size); | ||
| 378 | dbg(" _HPP: latency timer =0x%x\n", ab->_hpp->latency_timer); | ||
| 379 | dbg(" _HPP: enable SERR =0x%x\n", ab->_hpp->enable_serr); | ||
| 380 | dbg(" _HPP: enable PERR =0x%x\n", ab->_hpp->enable_perr); | ||
| 381 | } | ||
| 382 | } | ||
| 383 | |||
| 384 | static int shpchprm_delete_resource( | ||
| 385 | struct pci_resource **aprh, | ||
| 386 | ulong base, | ||
| 387 | ulong size) | ||
| 388 | { | ||
| 389 | struct pci_resource *res; | ||
| 390 | struct pci_resource *prevnode; | ||
| 391 | struct pci_resource *split_node; | ||
| 392 | ulong tbase; | ||
| 393 | |||
| 394 | shpchp_resource_sort_and_combine(aprh); | ||
| 395 | |||
| 396 | for (res = *aprh; res; res = res->next) { | ||
| 397 | if (res->base > base) | ||
| 398 | continue; | ||
| 399 | |||
| 400 | if ((res->base + res->length) < (base + size)) | ||
| 401 | continue; | ||
| 402 | |||
| 403 | if (res->base < base) { | ||
| 404 | tbase = base; | ||
| 405 | |||
| 406 | if ((res->length - (tbase - res->base)) < size) | ||
| 407 | continue; | ||
| 408 | |||
| 409 | split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); | ||
| 410 | if (!split_node) | ||
| 411 | return -ENOMEM; | ||
| 412 | |||
| 413 | split_node->base = res->base; | ||
| 414 | split_node->length = tbase - res->base; | ||
| 415 | res->base = tbase; | ||
| 416 | res->length -= split_node->length; | ||
| 417 | |||
| 418 | split_node->next = res->next; | ||
| 419 | res->next = split_node; | ||
| 420 | } | ||
| 421 | |||
| 422 | if (res->length >= size) { | ||
| 423 | split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); | ||
| 424 | if (!split_node) | ||
| 425 | return -ENOMEM; | ||
| 426 | |||
| 427 | split_node->base = res->base + size; | ||
| 428 | split_node->length = res->length - size; | ||
| 429 | res->length = size; | ||
| 430 | |||
| 431 | split_node->next = res->next; | ||
| 432 | res->next = split_node; | ||
| 433 | } | ||
| 434 | |||
| 435 | if (*aprh == res) { | ||
| 436 | *aprh = res->next; | ||
| 437 | } else { | ||
| 438 | prevnode = *aprh; | ||
| 439 | while (prevnode->next != res) | ||
| 440 | prevnode = prevnode->next; | ||
| 441 | |||
| 442 | prevnode->next = res->next; | ||
| 443 | } | ||
| 444 | res->next = NULL; | ||
| 445 | kfree(res); | ||
| 446 | break; | ||
| 447 | } | ||
| 448 | |||
| 449 | return 0; | ||
| 450 | } | ||
| 451 | |||
| 452 | static int shpchprm_delete_resources( | ||
| 453 | struct pci_resource **aprh, | ||
| 454 | struct pci_resource *this | ||
| 455 | ) | ||
| 456 | { | ||
| 457 | struct pci_resource *res; | ||
| 458 | |||
| 459 | for (res = this; res; res = res->next) | ||
| 460 | shpchprm_delete_resource(aprh, res->base, res->length); | ||
| 461 | |||
| 462 | return 0; | ||
| 463 | } | ||
| 464 | |||
| 465 | static int shpchprm_add_resource( | ||
| 466 | struct pci_resource **aprh, | ||
| 467 | ulong base, | ||
| 468 | ulong size) | ||
| 469 | { | ||
| 470 | struct pci_resource *res; | ||
| 471 | |||
| 472 | for (res = *aprh; res; res = res->next) { | ||
| 473 | if ((res->base + res->length) == base) { | ||
| 474 | res->length += size; | ||
| 475 | size = 0L; | ||
| 476 | break; | ||
| 477 | } | ||
| 478 | if (res->next == *aprh) | ||
| 479 | break; | ||
| 480 | } | ||
| 481 | |||
| 482 | if (size) { | ||
| 483 | res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); | ||
| 484 | if (!res) { | ||
| 485 | err ("acpi_shpchprm: alloc for res fail\n"); | ||
| 486 | return -ENOMEM; | ||
| 487 | } | ||
| 488 | memset(res, 0, sizeof (struct pci_resource)); | ||
| 489 | |||
| 490 | res->base = base; | ||
| 491 | res->length = size; | ||
| 492 | res->next = *aprh; | ||
| 493 | *aprh = res; | ||
| 494 | } | ||
| 495 | |||
| 496 | return 0; | ||
| 497 | } | ||
| 498 | |||
| 499 | static int shpchprm_add_resources( | ||
| 500 | struct pci_resource **aprh, | ||
| 501 | struct pci_resource *this | ||
| 502 | ) | ||
| 503 | { | ||
| 504 | struct pci_resource *res; | ||
| 505 | int rc = 0; | ||
| 506 | |||
| 507 | for (res = this; res && !rc; res = res->next) | ||
| 508 | rc = shpchprm_add_resource(aprh, res->base, res->length); | ||
| 509 | |||
| 510 | return rc; | ||
| 511 | } | ||
| 512 | |||
| 513 | static void acpi_parse_io ( | ||
| 514 | struct acpi_bridge *ab, | ||
| 515 | union acpi_resource_data *data | ||
| 516 | ) | ||
| 517 | { | ||
| 518 | struct acpi_resource_io *dataio; | ||
| 519 | dataio = (struct acpi_resource_io *) data; | ||
| 520 | |||
| 521 | dbg("Io Resource\n"); | ||
| 522 | dbg(" %d bit decode\n", ACPI_DECODE_16 == dataio->io_decode ? 16:10); | ||
| 523 | dbg(" Range minimum base: %08X\n", dataio->min_base_address); | ||
| 524 | dbg(" Range maximum base: %08X\n", dataio->max_base_address); | ||
| 525 | dbg(" Alignment: %08X\n", dataio->alignment); | ||
| 526 | dbg(" Range Length: %08X\n", dataio->range_length); | ||
| 527 | } | ||
| 528 | |||
| 529 | static void acpi_parse_fixed_io ( | ||
| 530 | struct acpi_bridge *ab, | ||
| 531 | union acpi_resource_data *data | ||
| 532 | ) | ||
| 533 | { | ||
| 534 | struct acpi_resource_fixed_io *datafio; | ||
| 535 | datafio = (struct acpi_resource_fixed_io *) data; | ||
| 536 | |||
| 537 | dbg("Fixed Io Resource\n"); | ||
| 538 | dbg(" Range base address: %08X", datafio->base_address); | ||
| 539 | dbg(" Range length: %08X", datafio->range_length); | ||
| 540 | } | ||
| 541 | |||
| 542 | static void acpi_parse_address16_32 ( | ||
| 543 | struct acpi_bridge *ab, | ||
| 544 | union acpi_resource_data *data, | ||
| 545 | acpi_resource_type id | ||
| 546 | ) | ||
| 547 | { | ||
| 548 | /* | ||
| 549 | * acpi_resource_address16 == acpi_resource_address32 | ||
| 550 | * acpi_resource_address16 *data16 = (acpi_resource_address16 *) data; | ||
| 551 | */ | ||
| 552 | struct acpi_resource_address32 *data32 = (struct acpi_resource_address32 *) data; | ||
| 553 | struct pci_resource **aprh, **tprh; | ||
| 554 | |||
| 555 | if (id == ACPI_RSTYPE_ADDRESS16) | ||
| 556 | dbg("acpi_shpchprm:16-Bit Address Space Resource\n"); | ||
| 557 | else | ||
| 558 | dbg("acpi_shpchprm:32-Bit Address Space Resource\n"); | ||
| 559 | |||
| 560 | switch (data32->resource_type) { | ||
| 561 | case ACPI_MEMORY_RANGE: | ||
| 562 | dbg(" Resource Type: Memory Range\n"); | ||
| 563 | aprh = &ab->mem_head; | ||
| 564 | tprh = &ab->tmem_head; | ||
| 565 | |||
| 566 | switch (data32->attribute.memory.cache_attribute) { | ||
| 567 | case ACPI_NON_CACHEABLE_MEMORY: | ||
| 568 | dbg(" Type Specific: Noncacheable memory\n"); | ||
| 569 | break; | ||
| 570 | case ACPI_CACHABLE_MEMORY: | ||
| 571 | dbg(" Type Specific: Cacheable memory\n"); | ||
| 572 | break; | ||
| 573 | case ACPI_WRITE_COMBINING_MEMORY: | ||
| 574 | dbg(" Type Specific: Write-combining memory\n"); | ||
| 575 | break; | ||
| 576 | case ACPI_PREFETCHABLE_MEMORY: | ||
| 577 | aprh = &ab->p_mem_head; | ||
| 578 | dbg(" Type Specific: Prefetchable memory\n"); | ||
| 579 | break; | ||
| 580 | default: | ||
| 581 | dbg(" Type Specific: Invalid cache attribute\n"); | ||
| 582 | break; | ||
| 583 | } | ||
| 584 | |||
| 585 | dbg(" Type Specific: Read%s\n", ACPI_READ_WRITE_MEMORY == data32->attribute.memory.read_write_attribute ? "/Write":" Only"); | ||
| 586 | break; | ||
| 587 | |||
| 588 | case ACPI_IO_RANGE: | ||
| 589 | dbg(" Resource Type: I/O Range\n"); | ||
| 590 | aprh = &ab->io_head; | ||
| 591 | tprh = &ab->tio_head; | ||
| 592 | |||
| 593 | switch (data32->attribute.io.range_attribute) { | ||
| 594 | case ACPI_NON_ISA_ONLY_RANGES: | ||
| 595 | dbg(" Type Specific: Non-ISA Io Addresses\n"); | ||
| 596 | break; | ||
| 597 | case ACPI_ISA_ONLY_RANGES: | ||
| 598 | dbg(" Type Specific: ISA Io Addresses\n"); | ||
| 599 | break; | ||
| 600 | case ACPI_ENTIRE_RANGE: | ||
| 601 | dbg(" Type Specific: ISA and non-ISA Io Addresses\n"); | ||
| 602 | break; | ||
| 603 | default: | ||
| 604 | dbg(" Type Specific: Invalid range attribute\n"); | ||
| 605 | break; | ||
| 606 | } | ||
| 607 | break; | ||
| 608 | |||
| 609 | case ACPI_BUS_NUMBER_RANGE: | ||
| 610 | dbg(" Resource Type: Bus Number Range(fixed)\n"); | ||
| 611 | /* fixup to be compatible with the rest of php driver */ | ||
| 612 | data32->min_address_range++; | ||
| 613 | data32->address_length--; | ||
| 614 | aprh = &ab->bus_head; | ||
| 615 | tprh = &ab->tbus_head; | ||
| 616 | break; | ||
| 617 | default: | ||
| 618 | dbg(" Resource Type: Invalid resource type. Exiting.\n"); | ||
| 619 | return; | ||
| 620 | } | ||
| 621 | |||
| 622 | dbg(" Resource %s\n", ACPI_CONSUMER == data32->producer_consumer ? "Consumer":"Producer"); | ||
| 623 | dbg(" %s decode\n", ACPI_SUB_DECODE == data32->decode ? "Subtractive":"Positive"); | ||
| 624 | dbg(" Min address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->min_address_fixed ? "":"not"); | ||
| 625 | dbg(" Max address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->max_address_fixed ? "":"not"); | ||
| 626 | dbg(" Granularity: %08X\n", data32->granularity); | ||
| 627 | dbg(" Address range min: %08X\n", data32->min_address_range); | ||
| 628 | dbg(" Address range max: %08X\n", data32->max_address_range); | ||
| 629 | dbg(" Address translation offset: %08X\n", data32->address_translation_offset); | ||
| 630 | dbg(" Address Length: %08X\n", data32->address_length); | ||
| 631 | |||
| 632 | if (0xFF != data32->resource_source.index) { | ||
| 633 | dbg(" Resource Source Index: %X\n", data32->resource_source.index); | ||
| 634 | /* dbg(" Resource Source: %s\n", data32->resource_source.string_ptr); */ | ||
| 635 | } | ||
| 636 | |||
| 637 | shpchprm_add_resource(aprh, data32->min_address_range, data32->address_length); | ||
| 638 | } | ||
| 639 | |||
| 640 | static acpi_status acpi_parse_crs( | ||
| 641 | struct acpi_bridge *ab, | ||
| 642 | struct acpi_resource *crsbuf | ||
| 643 | ) | ||
| 644 | { | ||
| 645 | acpi_status status = AE_OK; | ||
| 646 | struct acpi_resource *resource = crsbuf; | ||
| 647 | u8 count = 0; | ||
| 648 | u8 done = 0; | ||
| 649 | |||
| 650 | while (!done) { | ||
| 651 | dbg("acpi_shpchprm: PCI bus 0x%x Resource structure %x.\n", ab->bus, count++); | ||
| 652 | switch (resource->id) { | ||
| 653 | case ACPI_RSTYPE_IRQ: | ||
| 654 | dbg("Irq -------- Resource\n"); | ||
| 655 | break; | ||
| 656 | case ACPI_RSTYPE_DMA: | ||
| 657 | dbg("DMA -------- Resource\n"); | ||
| 658 | break; | ||
| 659 | case ACPI_RSTYPE_START_DPF: | ||
| 660 | dbg("Start DPF -------- Resource\n"); | ||
| 661 | break; | ||
| 662 | case ACPI_RSTYPE_END_DPF: | ||
| 663 | dbg("End DPF -------- Resource\n"); | ||
| 664 | break; | ||
| 665 | case ACPI_RSTYPE_IO: | ||
| 666 | acpi_parse_io (ab, &resource->data); | ||
| 667 | break; | ||
| 668 | case ACPI_RSTYPE_FIXED_IO: | ||
| 669 | acpi_parse_fixed_io (ab, &resource->data); | ||
| 670 | break; | ||
| 671 | case ACPI_RSTYPE_VENDOR: | ||
| 672 | dbg("Vendor -------- Resource\n"); | ||
| 673 | break; | ||
| 674 | case ACPI_RSTYPE_END_TAG: | ||
| 675 | dbg("End_tag -------- Resource\n"); | ||
| 676 | done = 1; | ||
| 677 | break; | ||
| 678 | case ACPI_RSTYPE_MEM24: | ||
| 679 | dbg("Mem24 -------- Resource\n"); | ||
| 680 | break; | ||
| 681 | case ACPI_RSTYPE_MEM32: | ||
| 682 | dbg("Mem32 -------- Resource\n"); | ||
| 683 | break; | ||
| 684 | case ACPI_RSTYPE_FIXED_MEM32: | ||
| 685 | dbg("Fixed Mem32 -------- Resource\n"); | ||
| 686 | break; | ||
| 687 | case ACPI_RSTYPE_ADDRESS16: | ||
| 688 | acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS16); | ||
| 689 | break; | ||
| 690 | case ACPI_RSTYPE_ADDRESS32: | ||
| 691 | acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS32); | ||
| 692 | break; | ||
| 693 | case ACPI_RSTYPE_ADDRESS64: | ||
| 694 | info("Address64 -------- Resource unparsed\n"); | ||
| 695 | break; | ||
| 696 | case ACPI_RSTYPE_EXT_IRQ: | ||
| 697 | dbg("Ext Irq -------- Resource\n"); | ||
| 698 | break; | ||
| 699 | default: | ||
| 700 | dbg("Invalid -------- resource type 0x%x\n", resource->id); | ||
| 701 | break; | ||
| 702 | } | ||
| 703 | |||
| 704 | resource = (struct acpi_resource *) ((char *)resource + resource->length); | ||
| 705 | } | ||
| 706 | |||
| 707 | return status; | ||
| 708 | } | ||
| 709 | |||
| 710 | static acpi_status acpi_get_crs( struct acpi_bridge *ab) | ||
| 711 | { | ||
| 712 | acpi_status status; | ||
| 713 | struct acpi_resource *crsbuf; | ||
| 714 | |||
| 715 | status = acpi_evaluate_crs(ab->handle, &crsbuf); | ||
| 716 | if (ACPI_SUCCESS(status)) { | ||
| 717 | status = acpi_parse_crs(ab, crsbuf); | ||
| 718 | kfree(crsbuf); | ||
| 719 | |||
| 720 | shpchp_resource_sort_and_combine(&ab->bus_head); | ||
| 721 | shpchp_resource_sort_and_combine(&ab->io_head); | ||
| 722 | shpchp_resource_sort_and_combine(&ab->mem_head); | ||
| 723 | shpchp_resource_sort_and_combine(&ab->p_mem_head); | ||
| 724 | |||
| 725 | shpchprm_add_resources (&ab->tbus_head, ab->bus_head); | ||
| 726 | shpchprm_add_resources (&ab->tio_head, ab->io_head); | ||
| 727 | shpchprm_add_resources (&ab->tmem_head, ab->mem_head); | ||
| 728 | shpchprm_add_resources (&ab->tp_mem_head, ab->p_mem_head); | ||
| 729 | } | ||
| 730 | |||
| 731 | return status; | ||
| 732 | } | ||
| 733 | |||
| 734 | /* find acpi_bridge downword from ab. */ | 240 | /* find acpi_bridge downword from ab. */ |
| 735 | static struct acpi_bridge * | 241 | static struct acpi_bridge * |
| 736 | find_acpi_bridge_by_bus( | 242 | find_acpi_bridge_by_bus( |
| @@ -1047,13 +553,6 @@ static struct acpi_bridge * add_host_bridge( | |||
| 1047 | ab->scanned = 0; | 553 | ab->scanned = 0; |
| 1048 | ab->type = BRIDGE_TYPE_HOST; | 554 | ab->type = BRIDGE_TYPE_HOST; |
| 1049 | 555 | ||
| 1050 | /* get root pci bridge's current resources */ | ||
| 1051 | status = acpi_get_crs(ab); | ||
| 1052 | if (ACPI_FAILURE(status)) { | ||
| 1053 | err("acpi_shpchprm:%s evaluate _CRS fail=0x%x\n", path_name, status); | ||
| 1054 | kfree(ab); | ||
| 1055 | return NULL; | ||
| 1056 | } | ||
| 1057 | build_a_bridge(ab, ab); | 556 | build_a_bridge(ab, ab); |
| 1058 | 557 | ||
| 1059 | return ab; | 558 | return ab; |
| @@ -1147,11 +646,6 @@ static void free_a_slot(struct acpi_php_slot *aps) | |||
| 1147 | { | 646 | { |
| 1148 | dbg(" free a php func of slot(0x%02x) on PCI b:d:f=0x%02x:%02x:%02x\n", aps->sun, aps->bus, aps->dev, aps->fun); | 647 | dbg(" free a php func of slot(0x%02x) on PCI b:d:f=0x%02x:%02x:%02x\n", aps->sun, aps->bus, aps->dev, aps->fun); |
| 1149 | 648 | ||
| 1150 | free_pci_resource (aps->io_head); | ||
| 1151 | free_pci_resource (aps->bus_head); | ||
| 1152 | free_pci_resource (aps->mem_head); | ||
| 1153 | free_pci_resource (aps->p_mem_head); | ||
| 1154 | |||
| 1155 | kfree(aps); | 649 | kfree(aps); |
| 1156 | } | 650 | } |
| 1157 | 651 | ||
| @@ -1176,15 +670,6 @@ static void free_a_bridge( struct acpi_bridge *ab) | |||
| 1176 | free_a_slot(aps); | 670 | free_a_slot(aps); |
| 1177 | } | 671 | } |
| 1178 | 672 | ||
| 1179 | free_pci_resource (ab->io_head); | ||
| 1180 | free_pci_resource (ab->tio_head); | ||
| 1181 | free_pci_resource (ab->bus_head); | ||
| 1182 | free_pci_resource (ab->tbus_head); | ||
| 1183 | free_pci_resource (ab->mem_head); | ||
| 1184 | free_pci_resource (ab->tmem_head); | ||
| 1185 | free_pci_resource (ab->p_mem_head); | ||
| 1186 | free_pci_resource (ab->tp_mem_head); | ||
| 1187 | |||
| 1188 | kfree(ab); | 673 | kfree(ab); |
| 1189 | } | 674 | } |
| 1190 | 675 | ||
| @@ -1234,47 +719,6 @@ static int get_number_of_slots ( | |||
| 1234 | return slot_num; | 719 | return slot_num; |
| 1235 | } | 720 | } |
| 1236 | 721 | ||
| 1237 | static int print_acpi_resources (struct acpi_bridge *ab) | ||
| 1238 | { | ||
| 1239 | struct acpi_php_slot *aps; | ||
| 1240 | int i; | ||
| 1241 | |||
| 1242 | switch (ab->type) { | ||
| 1243 | case BRIDGE_TYPE_HOST: | ||
| 1244 | dbg("PCI HOST Bridge (%x) [%s]\n", ab->bus, acpi_path_name(ab->handle)); | ||
| 1245 | break; | ||
| 1246 | case BRIDGE_TYPE_P2P: | ||
| 1247 | dbg("PCI P2P Bridge (%x-%x) [%s]\n", ab->pbus, ab->bus, acpi_path_name(ab->handle)); | ||
| 1248 | break; | ||
| 1249 | }; | ||
| 1250 | |||
| 1251 | print_pci_resources (ab); | ||
| 1252 | |||
| 1253 | for ( i = -1, aps = ab->slots; aps; aps = aps->next) { | ||
| 1254 | if (aps->dev == i) | ||
| 1255 | continue; | ||
| 1256 | dbg(" Slot sun(%x) s:b:d:f(%02x:%02x:%02x:%02x)\n", aps->sun, aps->seg, aps->bus, aps->dev, aps->fun); | ||
| 1257 | print_slot_resources(aps); | ||
| 1258 | i = aps->dev; | ||
| 1259 | } | ||
| 1260 | |||
| 1261 | if (ab->child) | ||
| 1262 | print_acpi_resources (ab->child); | ||
| 1263 | |||
| 1264 | if (ab->next) | ||
| 1265 | print_acpi_resources (ab->next); | ||
| 1266 | |||
| 1267 | return 0; | ||
| 1268 | } | ||
| 1269 | |||
| 1270 | int shpchprm_print_pirt(void) | ||
| 1271 | { | ||
| 1272 | dbg("SHPCHPRM ACPI Slots\n"); | ||
| 1273 | if (acpi_bridges_head) | ||
| 1274 | print_acpi_resources (acpi_bridges_head); | ||
| 1275 | return 0; | ||
| 1276 | } | ||
| 1277 | |||
| 1278 | static struct acpi_php_slot * get_acpi_slot ( | 722 | static struct acpi_php_slot * get_acpi_slot ( |
| 1279 | struct acpi_bridge *ab, | 723 | struct acpi_bridge *ab, |
| 1280 | u32 sun | 724 | u32 sun |
| @@ -1302,265 +746,6 @@ static struct acpi_php_slot * get_acpi_slot ( | |||
| 1302 | 746 | ||
| 1303 | } | 747 | } |
| 1304 | 748 | ||
| 1305 | #if 0 | ||
| 1306 | static void * shpchprm_get_slot(struct slot *slot) | ||
| 1307 | { | ||
| 1308 | struct acpi_bridge *ab = acpi_bridges_head; | ||
| 1309 | struct acpi_php_slot *aps = get_acpi_slot (ab, slot->number); | ||
| 1310 | |||
| 1311 | aps->slot = slot; | ||
| 1312 | |||
| 1313 | dbg("Got acpi slot sun(%x): s:b:d:f(%x:%x:%x:%x)\n", aps->sun, aps->seg, aps->bus, aps->dev, aps->fun); | ||
| 1314 | |||
| 1315 | return (void *)aps; | ||
| 1316 | } | ||
| 1317 | #endif | ||
| 1318 | |||
| 1319 | static void shpchprm_dump_func_res( struct pci_func *fun) | ||
| 1320 | { | ||
| 1321 | struct pci_func *func = fun; | ||
| 1322 | |||
| 1323 | if (func->bus_head) { | ||
| 1324 | dbg(": BUS Resources:\n"); | ||
| 1325 | print_pci_resource (func->bus_head); | ||
| 1326 | } | ||
| 1327 | if (func->io_head) { | ||
| 1328 | dbg(": IO Resources:\n"); | ||
| 1329 | print_pci_resource (func->io_head); | ||
| 1330 | } | ||
| 1331 | if (func->mem_head) { | ||
| 1332 | dbg(": MEM Resources:\n"); | ||
| 1333 | print_pci_resource (func->mem_head); | ||
| 1334 | } | ||
| 1335 | if (func->p_mem_head) { | ||
| 1336 | dbg(": PMEM Resources:\n"); | ||
| 1337 | print_pci_resource (func->p_mem_head); | ||
| 1338 | } | ||
| 1339 | } | ||
| 1340 | |||
| 1341 | static void shpchprm_dump_ctrl_res( struct controller *ctlr) | ||
| 1342 | { | ||
| 1343 | struct controller *ctrl = ctlr; | ||
| 1344 | |||
| 1345 | if (ctrl->bus_head) { | ||
| 1346 | dbg(": BUS Resources:\n"); | ||
| 1347 | print_pci_resource (ctrl->bus_head); | ||
| 1348 | } | ||
| 1349 | if (ctrl->io_head) { | ||
| 1350 | dbg(": IO Resources:\n"); | ||
| 1351 | print_pci_resource (ctrl->io_head); | ||
| 1352 | } | ||
| 1353 | if (ctrl->mem_head) { | ||
| 1354 | dbg(": MEM Resources:\n"); | ||
| 1355 | print_pci_resource (ctrl->mem_head); | ||
| 1356 | } | ||
| 1357 | if (ctrl->p_mem_head) { | ||
| 1358 | dbg(": PMEM Resources:\n"); | ||
| 1359 | print_pci_resource (ctrl->p_mem_head); | ||
| 1360 | } | ||
| 1361 | } | ||
| 1362 | |||
| 1363 | static int shpchprm_get_used_resources ( | ||
| 1364 | struct controller *ctrl, | ||
| 1365 | struct pci_func *func | ||
| 1366 | ) | ||
| 1367 | { | ||
| 1368 | return shpchp_save_used_resources (ctrl, func, !DISABLE_CARD); | ||
| 1369 | } | ||
| 1370 | |||
| 1371 | static int configure_existing_function( | ||
| 1372 | struct controller *ctrl, | ||
| 1373 | struct pci_func *func | ||
| 1374 | ) | ||
| 1375 | { | ||
| 1376 | int rc; | ||
| 1377 | |||
| 1378 | /* see how much resources the func has used. */ | ||
| 1379 | rc = shpchprm_get_used_resources (ctrl, func); | ||
| 1380 | |||
| 1381 | if (!rc) { | ||
| 1382 | /* subtract the resources used by the func from ctrl resources */ | ||
| 1383 | rc = shpchprm_delete_resources (&ctrl->bus_head, func->bus_head); | ||
| 1384 | rc |= shpchprm_delete_resources (&ctrl->io_head, func->io_head); | ||
| 1385 | rc |= shpchprm_delete_resources (&ctrl->mem_head, func->mem_head); | ||
| 1386 | rc |= shpchprm_delete_resources (&ctrl->p_mem_head, func->p_mem_head); | ||
| 1387 | if (rc) | ||
| 1388 | warn("aCEF: cannot del used resources\n"); | ||
| 1389 | } else | ||
| 1390 | err("aCEF: cannot get used resources\n"); | ||
| 1391 | |||
| 1392 | return rc; | ||
| 1393 | } | ||
| 1394 | |||
| 1395 | static int bind_pci_resources_to_slots ( struct controller *ctrl) | ||
| 1396 | { | ||
| 1397 | struct pci_func *func, new_func; | ||
| 1398 | int busn = ctrl->slot_bus; | ||
| 1399 | int devn, funn; | ||
| 1400 | u32 vid; | ||
| 1401 | |||
| 1402 | for (devn = 0; devn < 32; devn++) { | ||
| 1403 | for (funn = 0; funn < 8; funn++) { | ||
| 1404 | /* | ||
| 1405 | if (devn == ctrl->device && funn == ctrl->function) | ||
| 1406 | continue; | ||
| 1407 | */ | ||
| 1408 | /* find out if this entry is for an occupied slot */ | ||
| 1409 | vid = 0xFFFFFFFF; | ||
| 1410 | pci_bus_read_config_dword(ctrl->pci_dev->subordinate, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &vid); | ||
| 1411 | |||
| 1412 | if (vid != 0xFFFFFFFF) { | ||
| 1413 | func = shpchp_slot_find(busn, devn, funn); | ||
| 1414 | if (!func) { | ||
| 1415 | memset(&new_func, 0, sizeof(struct pci_func)); | ||
| 1416 | new_func.bus = busn; | ||
| 1417 | new_func.device = devn; | ||
| 1418 | new_func.function = funn; | ||
| 1419 | new_func.is_a_board = 1; | ||
| 1420 | configure_existing_function(ctrl, &new_func); | ||
| 1421 | shpchprm_dump_func_res(&new_func); | ||
| 1422 | } else { | ||
| 1423 | configure_existing_function(ctrl, func); | ||
| 1424 | shpchprm_dump_func_res(func); | ||
| 1425 | } | ||
| 1426 | dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus); | ||
| 1427 | } | ||
| 1428 | } | ||
| 1429 | } | ||
| 1430 | |||
| 1431 | return 0; | ||
| 1432 | } | ||
| 1433 | |||
| 1434 | static int bind_pci_resources( | ||
| 1435 | struct controller *ctrl, | ||
| 1436 | struct acpi_bridge *ab | ||
| 1437 | ) | ||
| 1438 | { | ||
| 1439 | int status = 0; | ||
| 1440 | |||
| 1441 | if (ab->bus_head) { | ||
| 1442 | dbg("bapr: BUS Resources add on PCI 0x%x\n", ab->bus); | ||
| 1443 | status = shpchprm_add_resources (&ctrl->bus_head, ab->bus_head); | ||
| 1444 | if (shpchprm_delete_resources (&ab->bus_head, ctrl->bus_head)) | ||
| 1445 | warn("bapr: cannot sub BUS Resource on PCI 0x%x\n", ab->bus); | ||
| 1446 | if (status) { | ||
| 1447 | err("bapr: BUS Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); | ||
| 1448 | return status; | ||
| 1449 | } | ||
| 1450 | } else | ||
| 1451 | info("bapr: No BUS Resource on PCI 0x%x.\n", ab->bus); | ||
| 1452 | |||
| 1453 | if (ab->io_head) { | ||
| 1454 | dbg("bapr: IO Resources add on PCI 0x%x\n", ab->bus); | ||
| 1455 | status = shpchprm_add_resources (&ctrl->io_head, ab->io_head); | ||
| 1456 | if (shpchprm_delete_resources (&ab->io_head, ctrl->io_head)) | ||
| 1457 | warn("bapr: cannot sub IO Resource on PCI 0x%x\n", ab->bus); | ||
| 1458 | if (status) { | ||
| 1459 | err("bapr: IO Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); | ||
| 1460 | return status; | ||
| 1461 | } | ||
| 1462 | } else | ||
| 1463 | info("bapr: No IO Resource on PCI 0x%x.\n", ab->bus); | ||
| 1464 | |||
| 1465 | if (ab->mem_head) { | ||
| 1466 | dbg("bapr: MEM Resources add on PCI 0x%x\n", ab->bus); | ||
| 1467 | status = shpchprm_add_resources (&ctrl->mem_head, ab->mem_head); | ||
| 1468 | if (shpchprm_delete_resources (&ab->mem_head, ctrl->mem_head)) | ||
| 1469 | warn("bapr: cannot sub MEM Resource on PCI 0x%x\n", ab->bus); | ||
| 1470 | if (status) { | ||
| 1471 | err("bapr: MEM Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); | ||
| 1472 | return status; | ||
| 1473 | } | ||
| 1474 | } else | ||
| 1475 | info("bapr: No MEM Resource on PCI 0x%x.\n", ab->bus); | ||
| 1476 | |||
| 1477 | if (ab->p_mem_head) { | ||
| 1478 | dbg("bapr: PMEM Resources add on PCI 0x%x\n", ab->bus); | ||
| 1479 | status = shpchprm_add_resources (&ctrl->p_mem_head, ab->p_mem_head); | ||
| 1480 | if (shpchprm_delete_resources (&ab->p_mem_head, ctrl->p_mem_head)) | ||
| 1481 | warn("bapr: cannot sub PMEM Resource on PCI 0x%x\n", ab->bus); | ||
| 1482 | if (status) { | ||
| 1483 | err("bapr: PMEM Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); | ||
| 1484 | return status; | ||
| 1485 | } | ||
| 1486 | } else | ||
| 1487 | info("bapr: No PMEM Resource on PCI 0x%x.\n", ab->bus); | ||
| 1488 | |||
| 1489 | return status; | ||
| 1490 | } | ||
| 1491 | |||
| 1492 | static int no_pci_resources( struct acpi_bridge *ab) | ||
| 1493 | { | ||
| 1494 | return !(ab->p_mem_head || ab->mem_head || ab->io_head || ab->bus_head); | ||
| 1495 | } | ||
| 1496 | |||
| 1497 | static int find_pci_bridge_resources ( | ||
| 1498 | struct controller *ctrl, | ||
| 1499 | struct acpi_bridge *ab | ||
| 1500 | ) | ||
| 1501 | { | ||
| 1502 | int rc = 0; | ||
| 1503 | struct pci_func func; | ||
| 1504 | |||
| 1505 | memset(&func, 0, sizeof(struct pci_func)); | ||
| 1506 | |||
| 1507 | func.bus = ab->pbus; | ||
| 1508 | func.device = ab->pdevice; | ||
| 1509 | func.function = ab->pfunction; | ||
| 1510 | func.is_a_board = 1; | ||
| 1511 | |||
| 1512 | /* Get used resources for this PCI bridge */ | ||
| 1513 | rc = shpchp_save_used_resources (ctrl, &func, !DISABLE_CARD); | ||
| 1514 | |||
| 1515 | ab->io_head = func.io_head; | ||
| 1516 | ab->mem_head = func.mem_head; | ||
| 1517 | ab->p_mem_head = func.p_mem_head; | ||
| 1518 | ab->bus_head = func.bus_head; | ||
| 1519 | if (ab->bus_head) | ||
| 1520 | shpchprm_delete_resource(&ab->bus_head, ctrl->bus, 1); | ||
| 1521 | |||
| 1522 | return rc; | ||
| 1523 | } | ||
| 1524 | |||
| 1525 | static int get_pci_resources_from_bridge( | ||
| 1526 | struct controller *ctrl, | ||
| 1527 | struct acpi_bridge *ab | ||
| 1528 | ) | ||
| 1529 | { | ||
| 1530 | int rc = 0; | ||
| 1531 | |||
| 1532 | dbg("grfb: Get Resources for PCI 0x%x from actual PCI bridge 0x%x.\n", ctrl->bus, ab->bus); | ||
| 1533 | |||
| 1534 | rc = find_pci_bridge_resources (ctrl, ab); | ||
| 1535 | |||
| 1536 | shpchp_resource_sort_and_combine(&ab->bus_head); | ||
| 1537 | shpchp_resource_sort_and_combine(&ab->io_head); | ||
| 1538 | shpchp_resource_sort_and_combine(&ab->mem_head); | ||
| 1539 | shpchp_resource_sort_and_combine(&ab->p_mem_head); | ||
| 1540 | |||
| 1541 | shpchprm_add_resources (&ab->tbus_head, ab->bus_head); | ||
| 1542 | shpchprm_add_resources (&ab->tio_head, ab->io_head); | ||
| 1543 | shpchprm_add_resources (&ab->tmem_head, ab->mem_head); | ||
| 1544 | shpchprm_add_resources (&ab->tp_mem_head, ab->p_mem_head); | ||
| 1545 | |||
| 1546 | return rc; | ||
| 1547 | } | ||
| 1548 | |||
| 1549 | static int get_pci_resources( | ||
| 1550 | struct controller *ctrl, | ||
| 1551 | struct acpi_bridge *ab | ||
| 1552 | ) | ||
| 1553 | { | ||
| 1554 | int rc = 0; | ||
| 1555 | |||
| 1556 | if (no_pci_resources(ab)) { | ||
| 1557 | dbg("spbr:PCI 0x%x has no resources. Get parent resources.\n", ab->bus); | ||
| 1558 | rc = get_pci_resources_from_bridge(ctrl, ab); | ||
| 1559 | } | ||
| 1560 | |||
| 1561 | return rc; | ||
| 1562 | } | ||
| 1563 | |||
| 1564 | int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) | 749 | int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) |
| 1565 | { | 750 | { |
| 1566 | int offset = devnum - ctrl->slot_device_offset; | 751 | int offset = devnum - ctrl->slot_device_offset; |
| @@ -1570,42 +755,6 @@ int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busn | |||
| 1570 | return 0; | 755 | return 0; |
| 1571 | } | 756 | } |
| 1572 | 757 | ||
| 1573 | /* | ||
| 1574 | * Get resources for this ctrl. | ||
| 1575 | * 1. get total resources from ACPI _CRS or bridge (this ctrl) | ||
| 1576 | * 2. find used resources of existing adapters | ||
| 1577 | * 3. subtract used resources from total resources | ||
| 1578 | */ | ||
| 1579 | int shpchprm_find_available_resources( struct controller *ctrl) | ||
| 1580 | { | ||
| 1581 | int rc = 0; | ||
| 1582 | struct acpi_bridge *ab; | ||
| 1583 | |||
| 1584 | ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->pci_dev->subordinate->number); | ||
| 1585 | if (!ab) { | ||
| 1586 | err("pfar:cannot locate acpi bridge of PCI 0x%x.\n", ctrl->pci_dev->subordinate->number); | ||
| 1587 | return -1; | ||
| 1588 | } | ||
| 1589 | if (no_pci_resources(ab)) { | ||
| 1590 | rc = get_pci_resources(ctrl, ab); | ||
| 1591 | if (rc) { | ||
| 1592 | err("pfar:cannot get pci resources of PCI 0x%x.\n",ctrl->pci_dev->subordinate->number); | ||
| 1593 | return -1; | ||
| 1594 | } | ||
| 1595 | } | ||
| 1596 | |||
| 1597 | rc = bind_pci_resources(ctrl, ab); | ||
| 1598 | dbg("pfar:pre-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl->pci_dev->subordinate->number); | ||
| 1599 | shpchprm_dump_ctrl_res(ctrl); | ||
| 1600 | |||
| 1601 | bind_pci_resources_to_slots (ctrl); | ||
| 1602 | |||
| 1603 | dbg("pfar:post-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl->pci_dev->subordinate->number); | ||
| 1604 | shpchprm_dump_ctrl_res(ctrl); | ||
| 1605 | |||
| 1606 | return rc; | ||
| 1607 | } | ||
| 1608 | |||
| 1609 | int shpchprm_set_hpp( | 758 | int shpchprm_set_hpp( |
| 1610 | struct controller *ctrl, | 759 | struct controller *ctrl, |
| 1611 | struct pci_func *func, | 760 | struct pci_func *func, |
diff --git a/drivers/pci/hotplug/shpchprm_legacy.c b/drivers/pci/hotplug/shpchprm_legacy.c index ba6c549c9b9d..6c27debe9522 100644 --- a/drivers/pci/hotplug/shpchprm_legacy.c +++ b/drivers/pci/hotplug/shpchprm_legacy.c | |||
| @@ -34,25 +34,11 @@ | |||
| 34 | #include <linux/pci.h> | 34 | #include <linux/pci.h> |
| 35 | #include <linux/init.h> | 35 | #include <linux/init.h> |
| 36 | #include <asm/uaccess.h> | 36 | #include <asm/uaccess.h> |
| 37 | #ifdef CONFIG_IA64 | ||
| 38 | #include <asm/iosapic.h> | ||
| 39 | #endif | ||
| 40 | #include "shpchp.h" | 37 | #include "shpchp.h" |
| 41 | #include "shpchprm.h" | 38 | #include "shpchprm.h" |
| 42 | #include "shpchprm_legacy.h" | ||
| 43 | |||
| 44 | static void __iomem *shpchp_rom_start; | ||
| 45 | static u16 unused_IRQ; | ||
| 46 | 39 | ||
| 47 | void shpchprm_cleanup(void) | 40 | void shpchprm_cleanup(void) |
| 48 | { | 41 | { |
| 49 | if (shpchp_rom_start) | ||
| 50 | iounmap(shpchp_rom_start); | ||
| 51 | } | ||
| 52 | |||
| 53 | int shpchprm_print_pirt(void) | ||
| 54 | { | ||
| 55 | return 0; | ||
| 56 | } | 42 | } |
| 57 | 43 | ||
| 58 | int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) | 44 | int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) |
| @@ -63,280 +49,6 @@ int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busn | |||
| 63 | return 0; | 49 | return 0; |
| 64 | } | 50 | } |
| 65 | 51 | ||
| 66 | /* Find the Hot Plug Resource Table in the specified region of memory */ | ||
| 67 | static void __iomem *detect_HRT_floating_pointer(void __iomem *begin, void __iomem *end) | ||
| 68 | { | ||
| 69 | void __iomem *fp; | ||
| 70 | void __iomem *endp; | ||
| 71 | u8 temp1, temp2, temp3, temp4; | ||
| 72 | int status = 0; | ||
| 73 | |||
| 74 | endp = (end - sizeof(struct hrt) + 1); | ||
| 75 | |||
| 76 | for (fp = begin; fp <= endp; fp += 16) { | ||
| 77 | temp1 = readb(fp + SIG0); | ||
| 78 | temp2 = readb(fp + SIG1); | ||
| 79 | temp3 = readb(fp + SIG2); | ||
| 80 | temp4 = readb(fp + SIG3); | ||
| 81 | if (temp1 == '$' && temp2 == 'H' && temp3 == 'R' && temp4 == 'T') { | ||
| 82 | status = 1; | ||
| 83 | break; | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | if (!status) | ||
| 88 | fp = NULL; | ||
| 89 | |||
| 90 | dbg("Discovered Hotplug Resource Table at %p\n", fp); | ||
| 91 | return fp; | ||
| 92 | } | ||
| 93 | |||
| 94 | /* | ||
| 95 | * shpchprm_find_available_resources | ||
| 96 | * | ||
| 97 | * Finds available memory, IO, and IRQ resources for programming | ||
| 98 | * devices which may be added to the system | ||
| 99 | * this function is for hot plug ADD! | ||
| 100 | * | ||
| 101 | * returns 0 if success | ||
| 102 | */ | ||
| 103 | int shpchprm_find_available_resources(struct controller *ctrl) | ||
| 104 | { | ||
| 105 | u8 populated_slot; | ||
| 106 | u8 bridged_slot; | ||
| 107 | void __iomem *one_slot; | ||
| 108 | struct pci_func *func = NULL; | ||
| 109 | int i = 10, index = 0; | ||
| 110 | u32 temp_dword, rc; | ||
| 111 | ulong temp_ulong; | ||
| 112 | struct pci_resource *mem_node; | ||
| 113 | struct pci_resource *p_mem_node; | ||
| 114 | struct pci_resource *io_node; | ||
| 115 | struct pci_resource *bus_node; | ||
| 116 | void __iomem *rom_resource_table; | ||
| 117 | struct pci_bus lpci_bus, *pci_bus; | ||
| 118 | u8 cfgspc_irq, temp; | ||
| 119 | |||
| 120 | memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); | ||
| 121 | pci_bus = &lpci_bus; | ||
| 122 | rom_resource_table = detect_HRT_floating_pointer(shpchp_rom_start, shpchp_rom_start + 0xffff); | ||
| 123 | dbg("rom_resource_table = %p\n", rom_resource_table); | ||
| 124 | if (rom_resource_table == NULL) | ||
| 125 | return -ENODEV; | ||
| 126 | |||
| 127 | /* Sum all resources and setup resource maps */ | ||
| 128 | unused_IRQ = readl(rom_resource_table + UNUSED_IRQ); | ||
| 129 | dbg("unused_IRQ = %x\n", unused_IRQ); | ||
| 130 | |||
| 131 | temp = 0; | ||
| 132 | while (unused_IRQ) { | ||
| 133 | if (unused_IRQ & 1) { | ||
| 134 | shpchp_disk_irq = temp; | ||
| 135 | break; | ||
| 136 | } | ||
| 137 | unused_IRQ = unused_IRQ >> 1; | ||
| 138 | temp++; | ||
| 139 | } | ||
| 140 | |||
| 141 | dbg("shpchp_disk_irq= %d\n", shpchp_disk_irq); | ||
| 142 | unused_IRQ = unused_IRQ >> 1; | ||
| 143 | temp++; | ||
| 144 | |||
| 145 | while (unused_IRQ) { | ||
| 146 | if (unused_IRQ & 1) { | ||
| 147 | shpchp_nic_irq = temp; | ||
| 148 | break; | ||
| 149 | } | ||
| 150 | unused_IRQ = unused_IRQ >> 1; | ||
| 151 | temp++; | ||
| 152 | } | ||
| 153 | |||
| 154 | dbg("shpchp_nic_irq= %d\n", shpchp_nic_irq); | ||
| 155 | unused_IRQ = readl(rom_resource_table + PCIIRQ); | ||
| 156 | |||
| 157 | temp = 0; | ||
| 158 | |||
| 159 | pci_read_config_byte(ctrl->pci_dev, PCI_INTERRUPT_LINE, &cfgspc_irq); | ||
| 160 | |||
| 161 | if (!shpchp_nic_irq) { | ||
| 162 | shpchp_nic_irq = cfgspc_irq; | ||
| 163 | } | ||
| 164 | |||
| 165 | if (!shpchp_disk_irq) { | ||
| 166 | shpchp_disk_irq = cfgspc_irq; | ||
| 167 | } | ||
| 168 | |||
| 169 | dbg("shpchp_disk_irq, shpchp_nic_irq= %d, %d\n", shpchp_disk_irq, shpchp_nic_irq); | ||
| 170 | |||
| 171 | one_slot = rom_resource_table + sizeof(struct hrt); | ||
| 172 | |||
| 173 | i = readb(rom_resource_table + NUMBER_OF_ENTRIES); | ||
| 174 | dbg("number_of_entries = %d\n", i); | ||
| 175 | |||
| 176 | if (!readb(one_slot + SECONDARY_BUS)) | ||
| 177 | return (1); | ||
| 178 | |||
| 179 | dbg("dev|IO base|length|MEMbase|length|PM base|length|PB SB MB\n"); | ||
| 180 | |||
| 181 | while (i && readb(one_slot + SECONDARY_BUS)) { | ||
| 182 | u8 dev_func = readb(one_slot + DEV_FUNC); | ||
| 183 | u8 primary_bus = readb(one_slot + PRIMARY_BUS); | ||
| 184 | u8 secondary_bus = readb(one_slot + SECONDARY_BUS); | ||
| 185 | u8 max_bus = readb(one_slot + MAX_BUS); | ||
| 186 | u16 io_base = readw(one_slot + IO_BASE); | ||
| 187 | u16 io_length = readw(one_slot + IO_LENGTH); | ||
| 188 | u16 mem_base = readw(one_slot + MEM_BASE); | ||
| 189 | u16 mem_length = readw(one_slot + MEM_LENGTH); | ||
| 190 | u16 pre_mem_base = readw(one_slot + PRE_MEM_BASE); | ||
| 191 | u16 pre_mem_length = readw(one_slot + PRE_MEM_LENGTH); | ||
| 192 | |||
| 193 | dbg("%2.2x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x |%2.2x %2.2x %2.2x\n", | ||
| 194 | dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length, | ||
| 195 | primary_bus, secondary_bus, max_bus); | ||
| 196 | |||
| 197 | /* If this entry isn't for our controller's bus, ignore it */ | ||
| 198 | if (primary_bus != ctrl->slot_bus) { | ||
| 199 | i--; | ||
| 200 | one_slot += sizeof(struct slot_rt); | ||
| 201 | continue; | ||
| 202 | } | ||
| 203 | /* find out if this entry is for an occupied slot */ | ||
| 204 | temp_dword = 0xFFFFFFFF; | ||
| 205 | pci_bus->number = primary_bus; | ||
| 206 | pci_bus_read_config_dword(pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword); | ||
| 207 | |||
| 208 | dbg("temp_D_word = %x\n", temp_dword); | ||
| 209 | |||
| 210 | if (temp_dword != 0xFFFFFFFF) { | ||
| 211 | index = 0; | ||
| 212 | func = shpchp_slot_find(primary_bus, dev_func >> 3, 0); | ||
| 213 | |||
| 214 | while (func && (func->function != (dev_func & 0x07))) { | ||
| 215 | dbg("func = %p b:d:f(%x:%x:%x)\n", func, primary_bus, dev_func >> 3, index); | ||
| 216 | func = shpchp_slot_find(primary_bus, dev_func >> 3, index++); | ||
| 217 | } | ||
| 218 | |||
| 219 | /* If we can't find a match, skip this table entry */ | ||
| 220 | if (!func) { | ||
| 221 | i--; | ||
| 222 | one_slot += sizeof(struct slot_rt); | ||
| 223 | continue; | ||
| 224 | } | ||
| 225 | /* this may not work and shouldn't be used */ | ||
| 226 | if (secondary_bus != primary_bus) | ||
| 227 | bridged_slot = 1; | ||
| 228 | else | ||
| 229 | bridged_slot = 0; | ||
| 230 | |||
| 231 | populated_slot = 1; | ||
| 232 | } else { | ||
| 233 | populated_slot = 0; | ||
| 234 | bridged_slot = 0; | ||
| 235 | } | ||
| 236 | dbg("slot populated =%s \n", populated_slot?"yes":"no"); | ||
| 237 | |||
| 238 | /* If we've got a valid IO base, use it */ | ||
| 239 | |||
| 240 | temp_ulong = io_base + io_length; | ||
| 241 | |||
| 242 | if ((io_base) && (temp_ulong <= 0x10000)) { | ||
| 243 | io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); | ||
| 244 | if (!io_node) | ||
| 245 | return -ENOMEM; | ||
| 246 | |||
| 247 | io_node->base = (ulong)io_base; | ||
| 248 | io_node->length = (ulong)io_length; | ||
| 249 | dbg("found io_node(base, length) = %x, %x\n", io_node->base, io_node->length); | ||
| 250 | |||
| 251 | if (!populated_slot) { | ||
| 252 | io_node->next = ctrl->io_head; | ||
| 253 | ctrl->io_head = io_node; | ||
| 254 | } else { | ||
| 255 | io_node->next = func->io_head; | ||
| 256 | func->io_head = io_node; | ||
| 257 | } | ||
| 258 | } | ||
| 259 | |||
| 260 | /* If we've got a valid memory base, use it */ | ||
| 261 | temp_ulong = mem_base + mem_length; | ||
| 262 | if ((mem_base) && (temp_ulong <= 0x10000)) { | ||
| 263 | mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); | ||
| 264 | if (!mem_node) | ||
| 265 | return -ENOMEM; | ||
| 266 | |||
| 267 | mem_node->base = (ulong)mem_base << 16; | ||
| 268 | mem_node->length = (ulong)(mem_length << 16); | ||
| 269 | dbg("found mem_node(base, length) = %x, %x\n", mem_node->base, mem_node->length); | ||
| 270 | |||
| 271 | if (!populated_slot) { | ||
| 272 | mem_node->next = ctrl->mem_head; | ||
| 273 | ctrl->mem_head = mem_node; | ||
| 274 | } else { | ||
| 275 | mem_node->next = func->mem_head; | ||
| 276 | func->mem_head = mem_node; | ||
| 277 | } | ||
| 278 | } | ||
| 279 | |||
| 280 | /* | ||
| 281 | * If we've got a valid prefetchable memory base, and | ||
| 282 | * the base + length isn't greater than 0xFFFF | ||
| 283 | */ | ||
| 284 | temp_ulong = pre_mem_base + pre_mem_length; | ||
| 285 | if ((pre_mem_base) && (temp_ulong <= 0x10000)) { | ||
| 286 | p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); | ||
| 287 | if (!p_mem_node) | ||
| 288 | return -ENOMEM; | ||
| 289 | |||
| 290 | p_mem_node->base = (ulong)pre_mem_base << 16; | ||
| 291 | p_mem_node->length = (ulong)pre_mem_length << 16; | ||
| 292 | dbg("found p_mem_node(base, length) = %x, %x\n", p_mem_node->base, p_mem_node->length); | ||
| 293 | |||
| 294 | if (!populated_slot) { | ||
| 295 | p_mem_node->next = ctrl->p_mem_head; | ||
| 296 | ctrl->p_mem_head = p_mem_node; | ||
| 297 | } else { | ||
| 298 | p_mem_node->next = func->p_mem_head; | ||
| 299 | func->p_mem_head = p_mem_node; | ||
| 300 | } | ||
| 301 | } | ||
| 302 | |||
| 303 | /* | ||
| 304 | * If we've got a valid bus number, use it | ||
| 305 | * The second condition is to ignore bus numbers on | ||
| 306 | * populated slots that don't have PCI-PCI bridges | ||
| 307 | */ | ||
| 308 | if (secondary_bus && (secondary_bus != primary_bus)) { | ||
| 309 | bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); | ||
| 310 | if (!bus_node) | ||
| 311 | return -ENOMEM; | ||
| 312 | |||
| 313 | bus_node->base = (ulong)secondary_bus; | ||
| 314 | bus_node->length = (ulong)(max_bus - secondary_bus + 1); | ||
| 315 | dbg("found bus_node(base, length) = %x, %x\n", bus_node->base, bus_node->length); | ||
| 316 | |||
| 317 | if (!populated_slot) { | ||
| 318 | bus_node->next = ctrl->bus_head; | ||
| 319 | ctrl->bus_head = bus_node; | ||
| 320 | } else { | ||
| 321 | bus_node->next = func->bus_head; | ||
| 322 | func->bus_head = bus_node; | ||
| 323 | } | ||
| 324 | } | ||
| 325 | |||
| 326 | i--; | ||
| 327 | one_slot += sizeof(struct slot_rt); | ||
| 328 | } | ||
| 329 | |||
| 330 | /* If all of the following fail, we don't have any resources for hot plug add */ | ||
| 331 | rc = 1; | ||
| 332 | rc &= shpchp_resource_sort_and_combine(&(ctrl->mem_head)); | ||
| 333 | rc &= shpchp_resource_sort_and_combine(&(ctrl->p_mem_head)); | ||
| 334 | rc &= shpchp_resource_sort_and_combine(&(ctrl->io_head)); | ||
| 335 | rc &= shpchp_resource_sort_and_combine(&(ctrl->bus_head)); | ||
| 336 | |||
| 337 | return (rc); | ||
| 338 | } | ||
| 339 | |||
| 340 | int shpchprm_set_hpp( | 52 | int shpchprm_set_hpp( |
| 341 | struct controller *ctrl, | 53 | struct controller *ctrl, |
| 342 | struct pci_func *func, | 54 | struct pci_func *func, |
| @@ -413,12 +125,6 @@ void shpchprm_enable_card( | |||
| 413 | 125 | ||
| 414 | static int legacy_shpchprm_init_pci(void) | 126 | static int legacy_shpchprm_init_pci(void) |
| 415 | { | 127 | { |
| 416 | shpchp_rom_start = ioremap(ROM_PHY_ADDR, ROM_PHY_LEN); | ||
| 417 | if (!shpchp_rom_start) { | ||
| 418 | err("Could not ioremap memory region for ROM\n"); | ||
| 419 | return -EIO; | ||
| 420 | } | ||
| 421 | |||
| 422 | return 0; | 128 | return 0; |
| 423 | } | 129 | } |
| 424 | 130 | ||
diff --git a/drivers/pci/hotplug/shpchprm_legacy.h b/drivers/pci/hotplug/shpchprm_legacy.h deleted file mode 100644 index 21bda74ddfa5..000000000000 --- a/drivers/pci/hotplug/shpchprm_legacy.h +++ /dev/null | |||
| @@ -1,113 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * SHPCHPRM Legacy: PHP Resource Manager for Non-ACPI/Legacy platform using HRT | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995,2001 Compaq Computer Corporation | ||
| 5 | * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) | ||
| 6 | * Copyright (C) 2001 IBM Corp. | ||
| 7 | * Copyright (C) 2003-2004 Intel Corporation | ||
| 8 | * | ||
| 9 | * All rights reserved. | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or modify | ||
| 12 | * it under the terms of the GNU General Public License as published by | ||
| 13 | * the Free Software Foundation; either version 2 of the License, or (at | ||
| 14 | * your option) any later version. | ||
| 15 | * | ||
| 16 | * This program is distributed in the hope that it will be useful, but | ||
| 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
| 19 | * NON INFRINGEMENT. See the GNU General Public License for more | ||
| 20 | * details. | ||
| 21 | * | ||
| 22 | * You should have received a copy of the GNU General Public License | ||
| 23 | * along with this program; if not, write to the Free Software | ||
| 24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 25 | * | ||
| 26 | * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com> | ||
| 27 | * | ||
| 28 | */ | ||
| 29 | |||
| 30 | #ifndef _SHPCHPRM_LEGACY_H_ | ||
| 31 | #define _SHPCHPRM_LEGACY_H_ | ||
| 32 | |||
| 33 | #define ROM_PHY_ADDR 0x0F0000 | ||
| 34 | #define ROM_PHY_LEN 0x00FFFF | ||
| 35 | |||
| 36 | struct slot_rt { | ||
| 37 | u8 dev_func; | ||
| 38 | u8 primary_bus; | ||
| 39 | u8 secondary_bus; | ||
| 40 | u8 max_bus; | ||
| 41 | u16 io_base; | ||
| 42 | u16 io_length; | ||
| 43 | u16 mem_base; | ||
| 44 | u16 mem_length; | ||
| 45 | u16 pre_mem_base; | ||
| 46 | u16 pre_mem_length; | ||
| 47 | } __attribute__ ((packed)); | ||
| 48 | |||
| 49 | /* offsets to the hotplug slot resource table registers based on the above structure layout */ | ||
| 50 | enum slot_rt_offsets { | ||
| 51 | DEV_FUNC = offsetof(struct slot_rt, dev_func), | ||
| 52 | PRIMARY_BUS = offsetof(struct slot_rt, primary_bus), | ||
| 53 | SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus), | ||
| 54 | MAX_BUS = offsetof(struct slot_rt, max_bus), | ||
| 55 | IO_BASE = offsetof(struct slot_rt, io_base), | ||
| 56 | IO_LENGTH = offsetof(struct slot_rt, io_length), | ||
| 57 | MEM_BASE = offsetof(struct slot_rt, mem_base), | ||
| 58 | MEM_LENGTH = offsetof(struct slot_rt, mem_length), | ||
| 59 | PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base), | ||
| 60 | PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length), | ||
| 61 | }; | ||
| 62 | |||
| 63 | struct hrt { | ||
| 64 | char sig0; | ||
| 65 | char sig1; | ||
| 66 | char sig2; | ||
| 67 | char sig3; | ||
| 68 | u16 unused_IRQ; | ||
| 69 | u16 PCIIRQ; | ||
| 70 | u8 number_of_entries; | ||
| 71 | u8 revision; | ||
| 72 | u16 reserved1; | ||
| 73 | u32 reserved2; | ||
| 74 | } __attribute__ ((packed)); | ||
| 75 | |||
| 76 | /* offsets to the hotplug resource table registers based on the above structure layout */ | ||
| 77 | enum hrt_offsets { | ||
| 78 | SIG0 = offsetof(struct hrt, sig0), | ||
| 79 | SIG1 = offsetof(struct hrt, sig1), | ||
| 80 | SIG2 = offsetof(struct hrt, sig2), | ||
| 81 | SIG3 = offsetof(struct hrt, sig3), | ||
| 82 | UNUSED_IRQ = offsetof(struct hrt, unused_IRQ), | ||
| 83 | PCIIRQ = offsetof(struct hrt, PCIIRQ), | ||
| 84 | NUMBER_OF_ENTRIES = offsetof(struct hrt, number_of_entries), | ||
| 85 | REVISION = offsetof(struct hrt, revision), | ||
| 86 | HRT_RESERVED1 = offsetof(struct hrt, reserved1), | ||
| 87 | HRT_RESERVED2 = offsetof(struct hrt, reserved2), | ||
| 88 | }; | ||
| 89 | |||
| 90 | struct irq_info { | ||
| 91 | u8 bus, devfn; /* bus, device and function */ | ||
| 92 | struct { | ||
| 93 | u8 link; /* IRQ line ID, chipset dependent, 0=not routed */ | ||
| 94 | u16 bitmap; /* Available IRQs */ | ||
| 95 | } __attribute__ ((packed)) irq[4]; | ||
| 96 | u8 slot; /* slot number, 0=onboard */ | ||
| 97 | u8 rfu; | ||
| 98 | } __attribute__ ((packed)); | ||
| 99 | |||
| 100 | struct irq_routing_table { | ||
| 101 | u32 signature; /* PIRQ_SIGNATURE should be here */ | ||
| 102 | u16 version; /* PIRQ_VERSION */ | ||
| 103 | u16 size; /* Table size in bytes */ | ||
| 104 | u8 rtr_bus, rtr_devfn; /* Where the interrupt router lies */ | ||
| 105 | u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */ | ||
| 106 | u16 rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */ | ||
| 107 | u32 miniport_data; /* Crap */ | ||
| 108 | u8 rfu[11]; | ||
| 109 | u8 checksum; /* Modulo 256 checksum must give zero */ | ||
| 110 | struct irq_info slots[0]; | ||
| 111 | } __attribute__ ((packed)); | ||
| 112 | |||
| 113 | #endif /* _SHPCHPRM_LEGACY_H_ */ | ||
diff --git a/drivers/pci/hotplug/shpchprm_nonacpi.c b/drivers/pci/hotplug/shpchprm_nonacpi.c index 5f75ef7f3df2..9d4ccae5f78e 100644 --- a/drivers/pci/hotplug/shpchprm_nonacpi.c +++ b/drivers/pci/hotplug/shpchprm_nonacpi.c | |||
| @@ -34,23 +34,14 @@ | |||
| 34 | #include <linux/pci.h> | 34 | #include <linux/pci.h> |
| 35 | #include <linux/init.h> | 35 | #include <linux/init.h> |
| 36 | #include <asm/uaccess.h> | 36 | #include <asm/uaccess.h> |
| 37 | #ifdef CONFIG_IA64 | ||
| 38 | #include <asm/iosapic.h> | ||
| 39 | #endif | ||
| 40 | #include "shpchp.h" | 37 | #include "shpchp.h" |
| 41 | #include "shpchprm.h" | 38 | #include "shpchprm.h" |
| 42 | #include "shpchprm_nonacpi.h" | ||
| 43 | 39 | ||
| 44 | void shpchprm_cleanup(void) | 40 | void shpchprm_cleanup(void) |
| 45 | { | 41 | { |
| 46 | return; | 42 | return; |
| 47 | } | 43 | } |
| 48 | 44 | ||
| 49 | int shpchprm_print_pirt(void) | ||
| 50 | { | ||
| 51 | return 0; | ||
| 52 | } | ||
| 53 | |||
| 54 | int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) | 45 | int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) |
| 55 | { | 46 | { |
| 56 | int offset = devnum - ctrl->slot_device_offset; | 47 | int offset = devnum - ctrl->slot_device_offset; |
| @@ -60,275 +51,6 @@ int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busn | |||
| 60 | return 0; | 51 | return 0; |
| 61 | } | 52 | } |
| 62 | 53 | ||
| 63 | static void print_pci_resource ( struct pci_resource *aprh) | ||
| 64 | { | ||
| 65 | struct pci_resource *res; | ||
| 66 | |||
| 67 | for (res = aprh; res; res = res->next) | ||
| 68 | dbg(" base= 0x%x length= 0x%x\n", res->base, res->length); | ||
| 69 | } | ||
| 70 | |||
| 71 | |||
| 72 | static void phprm_dump_func_res( struct pci_func *fun) | ||
| 73 | { | ||
| 74 | struct pci_func *func = fun; | ||
| 75 | |||
| 76 | if (func->bus_head) { | ||
| 77 | dbg(": BUS Resources:\n"); | ||
| 78 | print_pci_resource (func->bus_head); | ||
| 79 | } | ||
| 80 | if (func->io_head) { | ||
| 81 | dbg(": IO Resources:\n"); | ||
| 82 | print_pci_resource (func->io_head); | ||
| 83 | } | ||
| 84 | if (func->mem_head) { | ||
| 85 | dbg(": MEM Resources:\n"); | ||
| 86 | print_pci_resource (func->mem_head); | ||
| 87 | } | ||
| 88 | if (func->p_mem_head) { | ||
| 89 | dbg(": PMEM Resources:\n"); | ||
| 90 | print_pci_resource (func->p_mem_head); | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | static int phprm_get_used_resources ( | ||
| 95 | struct controller *ctrl, | ||
| 96 | struct pci_func *func | ||
| 97 | ) | ||
| 98 | { | ||
| 99 | return shpchp_save_used_resources (ctrl, func, !DISABLE_CARD); | ||
| 100 | } | ||
| 101 | |||
| 102 | static int phprm_delete_resource( | ||
| 103 | struct pci_resource **aprh, | ||
| 104 | ulong base, | ||
| 105 | ulong size) | ||
| 106 | { | ||
| 107 | struct pci_resource *res; | ||
| 108 | struct pci_resource *prevnode; | ||
| 109 | struct pci_resource *split_node; | ||
| 110 | ulong tbase; | ||
| 111 | |||
| 112 | shpchp_resource_sort_and_combine(aprh); | ||
| 113 | |||
| 114 | for (res = *aprh; res; res = res->next) { | ||
| 115 | if (res->base > base) | ||
| 116 | continue; | ||
| 117 | |||
| 118 | if ((res->base + res->length) < (base + size)) | ||
| 119 | continue; | ||
| 120 | |||
| 121 | if (res->base < base) { | ||
| 122 | tbase = base; | ||
| 123 | |||
| 124 | if ((res->length - (tbase - res->base)) < size) | ||
| 125 | continue; | ||
| 126 | |||
| 127 | split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); | ||
| 128 | if (!split_node) | ||
| 129 | return -ENOMEM; | ||
| 130 | |||
| 131 | split_node->base = res->base; | ||
| 132 | split_node->length = tbase - res->base; | ||
| 133 | res->base = tbase; | ||
| 134 | res->length -= split_node->length; | ||
| 135 | |||
| 136 | split_node->next = res->next; | ||
| 137 | res->next = split_node; | ||
| 138 | } | ||
| 139 | |||
| 140 | if (res->length >= size) { | ||
| 141 | split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); | ||
| 142 | if (!split_node) | ||
| 143 | return -ENOMEM; | ||
| 144 | |||
| 145 | split_node->base = res->base + size; | ||
| 146 | split_node->length = res->length - size; | ||
| 147 | res->length = size; | ||
| 148 | |||
| 149 | split_node->next = res->next; | ||
| 150 | res->next = split_node; | ||
| 151 | } | ||
| 152 | |||
| 153 | if (*aprh == res) { | ||
| 154 | *aprh = res->next; | ||
| 155 | } else { | ||
| 156 | prevnode = *aprh; | ||
| 157 | while (prevnode->next != res) | ||
| 158 | prevnode = prevnode->next; | ||
| 159 | |||
| 160 | prevnode->next = res->next; | ||
| 161 | } | ||
| 162 | res->next = NULL; | ||
| 163 | kfree(res); | ||
| 164 | break; | ||
| 165 | } | ||
| 166 | |||
| 167 | return 0; | ||
| 168 | } | ||
| 169 | |||
| 170 | |||
| 171 | static int phprm_delete_resources( | ||
| 172 | struct pci_resource **aprh, | ||
| 173 | struct pci_resource *this | ||
| 174 | ) | ||
| 175 | { | ||
| 176 | struct pci_resource *res; | ||
| 177 | |||
| 178 | for (res = this; res; res = res->next) | ||
| 179 | phprm_delete_resource(aprh, res->base, res->length); | ||
| 180 | |||
| 181 | return 0; | ||
| 182 | } | ||
| 183 | |||
| 184 | |||
| 185 | static int configure_existing_function( | ||
| 186 | struct controller *ctrl, | ||
| 187 | struct pci_func *func | ||
| 188 | ) | ||
| 189 | { | ||
| 190 | int rc; | ||
| 191 | |||
| 192 | /* see how much resources the func has used. */ | ||
| 193 | rc = phprm_get_used_resources (ctrl, func); | ||
| 194 | |||
| 195 | if (!rc) { | ||
| 196 | /* subtract the resources used by the func from ctrl resources */ | ||
| 197 | rc = phprm_delete_resources (&ctrl->bus_head, func->bus_head); | ||
| 198 | rc |= phprm_delete_resources (&ctrl->io_head, func->io_head); | ||
| 199 | rc |= phprm_delete_resources (&ctrl->mem_head, func->mem_head); | ||
| 200 | rc |= phprm_delete_resources (&ctrl->p_mem_head, func->p_mem_head); | ||
| 201 | if (rc) | ||
| 202 | warn("aCEF: cannot del used resources\n"); | ||
| 203 | } else | ||
| 204 | err("aCEF: cannot get used resources\n"); | ||
| 205 | |||
| 206 | return rc; | ||
| 207 | } | ||
| 208 | |||
| 209 | static int bind_pci_resources_to_slots ( struct controller *ctrl) | ||
| 210 | { | ||
| 211 | struct pci_func *func, new_func; | ||
| 212 | int busn = ctrl->slot_bus; | ||
| 213 | int devn, funn; | ||
| 214 | u32 vid; | ||
| 215 | |||
| 216 | for (devn = 0; devn < 32; devn++) { | ||
| 217 | for (funn = 0; funn < 8; funn++) { | ||
| 218 | /* | ||
| 219 | if (devn == ctrl->device && funn == ctrl->function) | ||
| 220 | continue; | ||
| 221 | */ | ||
| 222 | /* find out if this entry is for an occupied slot */ | ||
| 223 | vid = 0xFFFFFFFF; | ||
| 224 | |||
| 225 | pci_bus_read_config_dword(ctrl->pci_dev->subordinate, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &vid); | ||
| 226 | |||
| 227 | if (vid != 0xFFFFFFFF) { | ||
| 228 | func = shpchp_slot_find(busn, devn, funn); | ||
| 229 | if (!func) { | ||
| 230 | memset(&new_func, 0, sizeof(struct pci_func)); | ||
| 231 | new_func.bus = busn; | ||
| 232 | new_func.device = devn; | ||
| 233 | new_func.function = funn; | ||
| 234 | new_func.is_a_board = 1; | ||
| 235 | configure_existing_function(ctrl, &new_func); | ||
| 236 | phprm_dump_func_res(&new_func); | ||
| 237 | } else { | ||
| 238 | configure_existing_function(ctrl, func); | ||
| 239 | phprm_dump_func_res(func); | ||
| 240 | } | ||
| 241 | dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus); | ||
| 242 | } | ||
| 243 | } | ||
| 244 | } | ||
| 245 | |||
| 246 | return 0; | ||
| 247 | } | ||
| 248 | |||
| 249 | static void phprm_dump_ctrl_res( struct controller *ctlr) | ||
| 250 | { | ||
| 251 | struct controller *ctrl = ctlr; | ||
| 252 | |||
| 253 | if (ctrl->bus_head) { | ||
| 254 | dbg(": BUS Resources:\n"); | ||
| 255 | print_pci_resource (ctrl->bus_head); | ||
| 256 | } | ||
| 257 | if (ctrl->io_head) { | ||
| 258 | dbg(": IO Resources:\n"); | ||
| 259 | print_pci_resource (ctrl->io_head); | ||
| 260 | } | ||
| 261 | if (ctrl->mem_head) { | ||
| 262 | dbg(": MEM Resources:\n"); | ||
| 263 | print_pci_resource (ctrl->mem_head); | ||
| 264 | } | ||
| 265 | if (ctrl->p_mem_head) { | ||
| 266 | dbg(": PMEM Resources:\n"); | ||
| 267 | print_pci_resource (ctrl->p_mem_head); | ||
| 268 | } | ||
| 269 | } | ||
| 270 | |||
| 271 | /* | ||
| 272 | * phprm_find_available_resources | ||
| 273 | * | ||
| 274 | * Finds available memory, IO, and IRQ resources for programming | ||
| 275 | * devices which may be added to the system | ||
| 276 | * this function is for hot plug ADD! | ||
| 277 | * | ||
| 278 | * returns 0 if success | ||
| 279 | */ | ||
| 280 | int shpchprm_find_available_resources(struct controller *ctrl) | ||
| 281 | { | ||
| 282 | struct pci_func func; | ||
| 283 | u32 rc; | ||
| 284 | |||
| 285 | memset(&func, 0, sizeof(struct pci_func)); | ||
| 286 | |||
| 287 | func.bus = ctrl->bus; | ||
| 288 | func.device = ctrl->device; | ||
| 289 | func.function = ctrl->function; | ||
| 290 | func.is_a_board = 1; | ||
| 291 | |||
| 292 | /* Get resources for this PCI bridge */ | ||
| 293 | rc = shpchp_save_used_resources (ctrl, &func, !DISABLE_CARD); | ||
| 294 | dbg("%s: shpchp_save_used_resources rc = %d\n", __FUNCTION__, rc); | ||
| 295 | |||
| 296 | if (func.mem_head) | ||
| 297 | func.mem_head->next = ctrl->mem_head; | ||
| 298 | ctrl->mem_head = func.mem_head; | ||
| 299 | |||
| 300 | if (func.p_mem_head) | ||
| 301 | func.p_mem_head->next = ctrl->p_mem_head; | ||
| 302 | ctrl->p_mem_head = func.p_mem_head; | ||
| 303 | |||
| 304 | if (func.io_head) | ||
| 305 | func.io_head->next = ctrl->io_head; | ||
| 306 | ctrl->io_head = func.io_head; | ||
| 307 | |||
| 308 | if(func.bus_head) | ||
| 309 | func.bus_head->next = ctrl->bus_head; | ||
| 310 | ctrl->bus_head = func.bus_head; | ||
| 311 | if (ctrl->bus_head) | ||
| 312 | phprm_delete_resource(&ctrl->bus_head, ctrl->pci_dev->subordinate->number, 1); | ||
| 313 | |||
| 314 | dbg("%s:pre-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl->bus); | ||
| 315 | phprm_dump_ctrl_res(ctrl); | ||
| 316 | bind_pci_resources_to_slots (ctrl); | ||
| 317 | |||
| 318 | dbg("%s:post-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl->bus); | ||
| 319 | phprm_dump_ctrl_res(ctrl); | ||
| 320 | |||
| 321 | |||
| 322 | /* If all of the following fail, we don't have any resources for hot plug add */ | ||
| 323 | rc = 1; | ||
| 324 | rc &= shpchp_resource_sort_and_combine(&(ctrl->mem_head)); | ||
| 325 | rc &= shpchp_resource_sort_and_combine(&(ctrl->p_mem_head)); | ||
| 326 | rc &= shpchp_resource_sort_and_combine(&(ctrl->io_head)); | ||
| 327 | rc &= shpchp_resource_sort_and_combine(&(ctrl->bus_head)); | ||
| 328 | |||
| 329 | return (rc); | ||
| 330 | } | ||
| 331 | |||
| 332 | int shpchprm_set_hpp( | 54 | int shpchprm_set_hpp( |
| 333 | struct controller *ctrl, | 55 | struct controller *ctrl, |
| 334 | struct pci_func *func, | 56 | struct pci_func *func, |
diff --git a/drivers/pci/hotplug/shpchprm_nonacpi.h b/drivers/pci/hotplug/shpchprm_nonacpi.h deleted file mode 100644 index cddaaa5ee1b3..000000000000 --- a/drivers/pci/hotplug/shpchprm_nonacpi.h +++ /dev/null | |||
| @@ -1,56 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * SHPCHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995,2001 Compaq Computer Corporation | ||
| 5 | * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) | ||
| 6 | * Copyright (C) 2001 IBM Corp. | ||
| 7 | * Copyright (C) 2003-2004 Intel Corporation | ||
| 8 | * | ||
| 9 | * All rights reserved. | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or modify | ||
| 12 | * it under the terms of the GNU General Public License as published by | ||
| 13 | * the Free Software Foundation; either version 2 of the License, or (at | ||
| 14 | * your option) any later version. | ||
| 15 | * | ||
| 16 | * This program is distributed in the hope that it will be useful, but | ||
| 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
| 19 | * NON INFRINGEMENT. See the GNU General Public License for more | ||
| 20 | * details. | ||
| 21 | * | ||
| 22 | * You should have received a copy of the GNU General Public License | ||
| 23 | * along with this program; if not, write to the Free Software | ||
| 24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 25 | * | ||
| 26 | * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com> | ||
| 27 | * | ||
| 28 | */ | ||
| 29 | |||
| 30 | #ifndef _SHPCHPRM_NONACPI_H_ | ||
| 31 | #define _SHPCHPRM_NONACPI_H_ | ||
| 32 | |||
| 33 | struct irq_info { | ||
| 34 | u8 bus, devfn; /* bus, device and function */ | ||
| 35 | struct { | ||
| 36 | u8 link; /* IRQ line ID, chipset dependent, 0=not routed */ | ||
| 37 | u16 bitmap; /* Available IRQs */ | ||
| 38 | } __attribute__ ((packed)) irq[4]; | ||
| 39 | u8 slot; /* slot number, 0=onboard */ | ||
| 40 | u8 rfu; | ||
| 41 | } __attribute__ ((packed)); | ||
| 42 | |||
| 43 | struct irq_routing_table { | ||
| 44 | u32 signature; /* PIRQ_SIGNATURE should be here */ | ||
| 45 | u16 version; /* PIRQ_VERSION */ | ||
| 46 | u16 size; /* Table size in bytes */ | ||
| 47 | u8 rtr_bus, rtr_devfn; /* Where the interrupt router lies */ | ||
| 48 | u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */ | ||
| 49 | u16 rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */ | ||
| 50 | u32 miniport_data; /* Crap */ | ||
| 51 | u8 rfu[11]; | ||
| 52 | u8 checksum; /* Modulo 256 checksum must give zero */ | ||
| 53 | struct irq_info slots[0]; | ||
| 54 | } __attribute__ ((packed)); | ||
| 55 | |||
| 56 | #endif /* _SHPCHPRM_NONACPI_H_ */ | ||
