diff options
author | rajesh.shah@intel.com <rajesh.shah@intel.com> | 2005-10-13 12:05:36 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-10-28 15:36:59 -0700 |
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 b7d1c61d6bb..deea56c73cf 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -63,14 +63,7 @@ struct pci_func { u8 switch_save; u8 presence_save; u8 pwr_save; - u32 base_length[0x06]; - u8 base_type[0x06]; - u16 reserved2; u32 config_space[0x20]; - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; struct pci_dev* pci_dev; }; @@ -96,12 +89,6 @@ struct slot { struct list_head slot_list; }; -struct pci_resource { - struct pci_resource * next; - u32 base; - u32 length; -}; - struct event_info { u32 event_type; u8 hp_slot; @@ -113,10 +100,6 @@ struct controller { void * hpc_ctlr_handle; /* HPC controller handle */ int num_slots; /* Number of slots on ctlr */ int slot_num_inc; /* 1 or -1 */ - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; struct pci_dev *pci_dev; struct pci_bus *pci_bus; struct event_info event_queue[10]; @@ -139,20 +122,6 @@ struct controller { u16 vendor_id; }; -struct irq_mapping { - u8 barber_pole; - u8 valid_INT; - u8 interrupt[4]; -}; - -struct resource_lists { - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; - struct irq_mapping *irqs; -}; - /* Define AMD SHPC ID */ #define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450 @@ -197,7 +166,6 @@ struct resource_lists { #define msg_HPC_rev_error "Unsupported revision of the PCI hot plug controller found.\n" #define msg_HPC_non_shpc "The PCI hot plug controller is not supported by this driver.\n" #define msg_HPC_not_supported "This system is not supported by this version of shpcphd mdoule. Upgrade to a newer version of shpchpd\n" -#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" #define msg_button_on "PCI slot #%d - powering on due to button press.\n" #define msg_button_off "PCI slot #%d - powering off due to button press.\n" #define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n" @@ -207,7 +175,6 @@ struct resource_lists { extern void shpchp_create_ctrl_files (struct controller *ctrl); /* controller functions */ -extern int shpchprm_find_available_resources(struct controller *ctrl); extern int shpchp_event_start_thread(void); extern void shpchp_event_stop_thread(void); 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); extern u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id); extern u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id); -/* resource functions */ -extern int shpchp_resource_sort_and_combine(struct pci_resource **head); - /* pci functions */ -extern int shpchp_set_irq(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num); -/*extern int shpchp_get_bus_dev(struct controller *ctrl, u8 *bus_num, u8 *dev_num, struct slot *slot);*/ extern int shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num); -extern int shpchp_save_used_resources(struct controller *ctrl, struct pci_func * func, int flag); extern int shpchp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot); -extern void shpchp_destroy_board_resources(struct pci_func * func); -extern int shpchp_return_board_resources(struct pci_func * func, struct resource_lists * resources); -extern void shpchp_destroy_resource_list(struct resource_lists * resources); -extern int shpchp_configure_device(struct controller* ctrl, struct pci_func* func); +extern int shpchp_configure_device(struct slot *p_slot); extern int shpchp_unconfigure_device(struct pci_func* func); @@ -240,10 +198,6 @@ extern int shpchp_unconfigure_device(struct pci_func* func); extern struct controller *shpchp_ctrl_list; extern struct pci_func *shpchp_slot_list[256]; -/* These are added to support AMD shpc */ -extern u8 shpchp_nic_irq; -extern u8 shpchp_disk_irq; - struct ctrl_reg { volatile u32 base_offset; volatile u32 slot_avail1; @@ -398,15 +352,6 @@ static inline int wait_for_ctrl_irq (struct controller *ctrl) return retval; } -/* Puts node back in the resource list pointed to by head */ -static inline void return_resource(struct pci_resource **head, struct pci_resource *node) -{ - if (!node || !head) - return; - node->next = *head; - *head = node; -} - #define SLOT_NAME_SIZE 10 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 6f7d8a29957..8f5da504df3 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) goto err_out_free_ctrl_bus; } - /* Get IO, memory, and IRQ resources for new devices */ - rc = shpchprm_find_available_resources(ctrl); - ctrl->add_support = !rc; + ctrl->add_support = 1; - if (rc) { - dbg("shpchprm_find_available_resources = %#x\n", rc); - err("unable to locate PCI configuration resources for hot plug add.\n"); - goto err_out_free_ctrl_bus; - } - /* Setup the slot information structures */ rc = init_slots(ctrl); if (rc) { @@ -497,18 +489,6 @@ static int shpc_start_thread(void) return retval; } -static inline void __exit -free_shpchp_res(struct pci_resource *res) -{ - struct pci_resource *tres; - - while (res) { - tres = res; - res = res->next; - kfree(tres); - } -} - static void __exit unload_shpchpd(void) { struct pci_func *next; @@ -522,11 +502,6 @@ static void __exit unload_shpchpd(void) while (ctrl) { cleanup_slots(ctrl); - free_shpchp_res(ctrl->io_head); - free_shpchp_res(ctrl->mem_head); - free_shpchp_res(ctrl->p_mem_head); - free_shpchp_res(ctrl->bus_head); - kfree (ctrl->pci_bus); dbg("%s: calling release_ctlr\n", __FUNCTION__); @@ -541,11 +516,6 @@ static void __exit unload_shpchpd(void) for (loop = 0; loop < 256; loop++) { next = shpchp_slot_list[loop]; while (next != NULL) { - free_shpchp_res(next->io_head); - free_shpchp_res(next->mem_head); - free_shpchp_res(next->p_mem_head); - free_shpchp_res(next->bus_head); - TempSlot = next; next = next->next; kfree(TempSlot); @@ -607,9 +577,7 @@ error_hpc_init: if (retval) { shpchprm_cleanup(); shpchp_event_stop_thread(); - } else - shpchprm_print_pirt(); - + } return retval; } diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 91c9903e621..aa507e453e4 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -38,13 +38,10 @@ #include <linux/wait.h> #include <linux/smp_lock.h> #include <linux/pci.h> +#include "../pci.h" #include "shpchp.h" #include "shpchprm.h" -static u32 configure_new_device(struct controller *ctrl, struct pci_func *func, - u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev); -static int configure_new_function( struct controller *ctrl, struct pci_func *func, - u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev); static void interrupt_event_handler(struct controller *ctrl); 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 static int event_finished; static unsigned long pushbutton_pending; /* = 0 */ -u8 shpchp_disk_irq; -u8 shpchp_nic_irq; - u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id) { struct controller *ctrl = (struct controller *) inst_id; @@ -260,624 +254,6 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) return rc; } - -/* - * sort_by_size - * - * Sorts nodes on the list by their length. - * Smallest first. - * - */ -static int sort_by_size(struct pci_resource **head) -{ - struct pci_resource *current_res; - struct pci_resource *next_res; - int out_of_order = 1; - - if (!(*head)) - return(1); - - if (!((*head)->next)) - return(0); - - while (out_of_order) { - out_of_order = 0; - - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->length > (*head)->next->length)) { - out_of_order++; - current_res = *head; - *head = (*head)->next; - current_res->next = (*head)->next; - (*head)->next = current_res; - } - - current_res = *head; - - while (current_res->next && current_res->next->next) { - if (current_res->next->length > current_res->next->next->length) { - out_of_order++; - next_res = current_res->next; - current_res->next = current_res->next->next; - current_res = current_res->next; - next_res->next = current_res->next; - current_res->next = next_res; - } else - current_res = current_res->next; - } - } /* End of out_of_order loop */ - - return(0); -} - - -/* - * sort_by_max_size - * - * Sorts nodes on the list by their length. - * Largest first. - * - */ -static int sort_by_max_size(struct pci_resource **head) -{ - struct pci_resource *current_res; - struct pci_resource *next_res; - int out_of_order = 1; - - if (!(*head)) - return(1); - - if (!((*head)->next)) - return(0); - - while (out_of_order) { - out_of_order = 0; - - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->length < (*head)->next->length)) { - out_of_order++; - current_res = *head; - *head = (*head)->next; - current_res->next = (*head)->next; - (*head)->next = current_res; - } - - current_res = *head; - - while (current_res->next && current_res->next->next) { - if (current_res->next->length < current_res->next->next->length) { - out_of_order++; - next_res = current_res->next; - current_res->next = current_res->next->next; - current_res = current_res->next; - next_res->next = current_res->next; - current_res->next = next_res; - } else - current_res = current_res->next; - } - } /* End of out_of_order loop */ - - return(0); -} - - -/* - * do_pre_bridge_resource_split - * - * Returns zero or one node of resources that aren't in use - * - */ -static struct pci_resource *do_pre_bridge_resource_split (struct pci_resource **head, struct pci_resource **orig_head, u32 alignment) -{ - struct pci_resource *prevnode = NULL; - struct pci_resource *node; - struct pci_resource *split_node; - u32 rc; - u32 temp_dword; - dbg("do_pre_bridge_resource_split\n"); - - if (!(*head) || !(*orig_head)) - return(NULL); - - rc = shpchp_resource_sort_and_combine(head); - - if (rc) - return(NULL); - - if ((*head)->base != (*orig_head)->base) - return(NULL); - - if ((*head)->length == (*orig_head)->length) - return(NULL); - - - /* If we got here, there the bridge requires some of the resource, but - * we may be able to split some off of the front - */ - node = *head; - - if (node->length & (alignment -1)) { - /* This one isn't an aligned length, so we'll make a new entry - * and split it up. - */ - split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); - - if (!split_node) - return(NULL); - - temp_dword = (node->length | (alignment-1)) + 1 - alignment; - - split_node->base = node->base; - split_node->length = temp_dword; - - node->length -= temp_dword; - node->base += split_node->length; - - /* Put it in the list */ - *head = split_node; - split_node->next = node; - } - - if (node->length < alignment) { - return(NULL); - } - - /* Now unlink it */ - if (*head == node) { - *head = node->next; - node->next = NULL; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - node->next = NULL; - } - - return(node); -} - - -/* - * do_bridge_resource_split - * - * Returns zero or one node of resources that aren't in use - * - */ -static struct pci_resource *do_bridge_resource_split (struct pci_resource **head, u32 alignment) -{ - struct pci_resource *prevnode = NULL; - struct pci_resource *node; - u32 rc; - u32 temp_dword; - - if (!(*head)) - return(NULL); - - rc = shpchp_resource_sort_and_combine(head); - - if (rc) - return(NULL); - - node = *head; - - while (node->next) { - prevnode = node; - node = node->next; - kfree(prevnode); - } - - if (node->length < alignment) { - kfree(node); - return(NULL); - } - - if (node->base & (alignment - 1)) { - /* Short circuit if adjusted size is too small */ - temp_dword = (node->base | (alignment-1)) + 1; - if ((node->length - (temp_dword - node->base)) < alignment) { - kfree(node); - return(NULL); - } - - node->length -= (temp_dword - node->base); - node->base = temp_dword; - } - - if (node->length & (alignment - 1)) { - /* There's stuff in use after this node */ - kfree(node); - return(NULL); - } - - return(node); -} - - -/* - * get_io_resource - * - * this function sorts the resource list by size and then - * returns the first node of "size" length that is not in the - * ISA aliasing window. If it finds a node larger than "size" - * it will split it up. - * - * size must be a power of two. - */ -static struct pci_resource *get_io_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node = NULL; - u32 temp_dword; - - if (!(*head)) - return(NULL); - - if ( shpchp_resource_sort_and_combine(head) ) - return(NULL); - - if ( sort_by_size(head) ) - return(NULL); - - for (node = *head; node; node = node->next) { - if (node->length < size) - continue; - - if (node->base & (size - 1)) { - /* This one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_dword = (node->base | (size-1)) + 1; - - /*/ Short circuit if adjusted size is too small */ - if ((node->length - (temp_dword - node->base)) < size) - continue; - - split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = node->base; - split_node->length = temp_dword - node->base; - node->base = temp_dword; - node->length -= split_node->length; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of non-aligned base */ - - /* Don't need to check if too small since we already did */ - if (node->length > size) { - /* This one is longer than we need - so we'll make a new entry and split it up */ - split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = node->base + size; - split_node->length = node->length - size; - node->length = size; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of too big on top end */ - - /* For IO make sure it's not in the ISA aliasing space */ - if (node->base & 0x300L) - continue; - - /* If we got here, then it is the right size - Now take it out of the list */ - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - } - node->next = NULL; - /* Stop looping */ - break; - } - - return(node); -} - - -/* - * get_max_resource - * - * Gets the largest node that is at least "size" big from the - * list pointed to by head. It aligns the node on top and bottom - * to "size" alignment before returning it. - * J.I. modified to put max size limits of; 64M->32M->16M->8M->4M->1M - * This is needed to avoid allocating entire ACPI _CRS res to one child bridge/slot. - */ -static struct pci_resource *get_max_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *max; - struct pci_resource *temp; - struct pci_resource *split_node; - u32 temp_dword; - u32 max_size[] = { 0x4000000, 0x2000000, 0x1000000, 0x0800000, 0x0400000, 0x0200000, 0x0100000, 0x00 }; - int i; - - if (!(*head)) - return(NULL); - - if (shpchp_resource_sort_and_combine(head)) - return(NULL); - - if (sort_by_max_size(head)) - return(NULL); - - for (max = *head;max; max = max->next) { - - /* If not big enough we could probably just bail, - instead we'll continue to the next. */ - if (max->length < size) - continue; - - if (max->base & (size - 1)) { - /* This one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_dword = (max->base | (size-1)) + 1; - - /* Short circuit if adjusted size is too small */ - if ((max->length - (temp_dword - max->base)) < size) - continue; - - split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = max->base; - split_node->length = temp_dword - max->base; - max->base = temp_dword; - max->length -= split_node->length; - - /* Put it next in the list */ - split_node->next = max->next; - max->next = split_node; - } - - if ((max->base + max->length) & (size - 1)) { - /* This one isn't end aligned properly at the top - so we'll make a new entry and split it up */ - split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); - - if (!split_node) - return(NULL); - temp_dword = ((max->base + max->length) & ~(size - 1)); - split_node->base = temp_dword; - split_node->length = max->length + max->base - - split_node->base; - max->length -= split_node->length; - - /* Put it in the list */ - split_node->next = max->next; - max->next = split_node; - } - - /* Make sure it didn't shrink too much when we aligned it */ - if (max->length < size) - continue; - - for ( i = 0; max_size[i] > size; i++) { - if (max->length > max_size[i]) { - split_node = kmalloc(sizeof(*split_node), - GFP_KERNEL); - if (!split_node) - break; /* return (NULL); */ - split_node->base = max->base + max_size[i]; - split_node->length = max->length - max_size[i]; - max->length = max_size[i]; - /* Put it next in the list */ - split_node->next = max->next; - max->next = split_node; - break; - } - } - - /* Now take it out of the list */ - temp = (struct pci_resource*) *head; - if (temp == max) { - *head = max->next; - } else { - while (temp && temp->next != max) { - temp = temp->next; - } - - temp->next = max->next; - } - - max->next = NULL; - return(max); - } - - /* If we get here, we couldn't find one */ - return(NULL); -} - - -/* - * get_resource - * - * this function sorts the resource list by size and then - * returns the first node of "size" length. If it finds a node - * larger than "size" it will split it up. - * - * size must be a power of two. - */ -static struct pci_resource *get_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node; - u32 temp_dword; - - if (!(*head)) - return(NULL); - - if ( shpchp_resource_sort_and_combine(head) ) - return(NULL); - - if ( sort_by_size(head) ) - return(NULL); - - for (node = *head; node; node = node->next) { - dbg("%s: req_size =0x%x node=%p, base=0x%x, length=0x%x\n", - __FUNCTION__, size, node, node->base, node->length); - if (node->length < size) - continue; - - if (node->base & (size - 1)) { - dbg("%s: not aligned\n", __FUNCTION__); - /* this one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_dword = (node->base | (size-1)) + 1; - - /* Short circuit if adjusted size is too small */ - if ((node->length - (temp_dword - node->base)) < size) - continue; - - split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = node->base; - split_node->length = temp_dword - node->base; - node->base = temp_dword; - node->length -= split_node->length; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of non-aligned base */ - - /* Don't need to check if too small since we already did */ - if (node->length > size) { - dbg("%s: too big\n", __FUNCTION__); - /* this one is longer than we need - so we'll make a new entry and split it up */ - split_node = kmalloc(sizeof(*split_node), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = node->base + size; - split_node->length = node->length - size; - node->length = size; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of too big on top end */ - - dbg("%s: got one!!!\n", __FUNCTION__); - /* If we got here, then it is the right size - Now take it out of the list */ - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - } - node->next = NULL; - /* Stop looping */ - break; - } - return(node); -} - - -/* - * shpchp_resource_sort_and_combine - * - * Sorts all of the nodes in the list in ascending order by - * their base addresses. Also does garbage collection by - * combining adjacent nodes. - * - * returns 0 if success - */ -int shpchp_resource_sort_and_combine(struct pci_resource **head) -{ - struct pci_resource *node1; - struct pci_resource *node2; - int out_of_order = 1; - - dbg("%s: head = %p, *head = %p\n", __FUNCTION__, head, *head); - - if (!(*head)) - return(1); - - dbg("*head->next = %p\n",(*head)->next); - - if (!(*head)->next) - return(0); /* only one item on the list, already sorted! */ - - dbg("*head->base = 0x%x\n",(*head)->base); - dbg("*head->next->base = 0x%x\n",(*head)->next->base); - while (out_of_order) { - out_of_order = 0; - - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->base > (*head)->next->base)) { - node1 = *head; - (*head) = (*head)->next; - node1->next = (*head)->next; - (*head)->next = node1; - out_of_order++; - } - - node1 = (*head); - - while (node1->next && node1->next->next) { - if (node1->next->base > node1->next->next->base) { - out_of_order++; - node2 = node1->next; - node1->next = node1->next->next; - node1 = node1->next; - node2->next = node1->next; - node1->next = node2; - } else - node1 = node1->next; - } - } /* End of out_of_order loop */ - - node1 = *head; - - while (node1 && node1->next) { - if ((node1->base + node1->length) == node1->next->base) { - /* Combine */ - dbg("8..\n"); - node1->length += node1->next->length; - node2 = node1->next; - node1->next = node1->next->next; - kfree(node2); - } else - node1 = node1->next; - } - - return(0); -} - - /** * shpchp_slot_create - Creates a node and adds it to the proper bus. * @busnumber - bus where new node is to be located @@ -933,7 +309,6 @@ static int slot_remove(struct pci_func * old_slot) if (next == old_slot) { shpchp_slot_list[old_slot->bus] = old_slot->next; - shpchp_destroy_board_resources(old_slot); kfree(old_slot); return(0); } @@ -944,7 +319,6 @@ static int slot_remove(struct pci_func * old_slot) if (next->next == old_slot) { next->next = old_slot->next; - shpchp_destroy_board_resources(old_slot); kfree(old_slot); return(0); } else @@ -1120,12 +494,8 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl) { u8 hp_slot; u8 slots_not_empty = 0; - int index; - u32 temp_register = 0xFFFFFFFF; - u32 retval, rc = 0; - struct pci_func *new_func = NULL; + u32 rc = 0; struct slot *p_slot; - struct resource_lists res_lists; enum pci_bus_speed adapter_speed, bus_speed, max_bus_speed; u8 pi, mode; @@ -1328,135 +698,65 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl) /* Check for a power fault */ if (func->status == 0xFF) { /* power fault occurred, but it was benign */ - temp_register = 0xFFFFFFFF; - dbg("%s: temp register set to %x by power fault\n", __FUNCTION__, temp_register); + dbg("%s: power fault\n", __FUNCTION__); rc = POWER_FAILURE; func->status = 0; - } else { - /* Get vendor/device ID u32 */ - rc = pci_bus_read_config_dword (ctrl->pci_dev->subordinate, PCI_DEVFN(func->device, func->function), - PCI_VENDOR_ID, &temp_register); - dbg("%s: pci_bus_read_config_dword returns %d\n", __FUNCTION__, rc); - dbg("%s: temp_register is %x\n", __FUNCTION__, temp_register); - - if (rc != 0) { - /* Something's wrong here */ - temp_register = 0xFFFFFFFF; - dbg("%s: temp register set to %x by error\n", __FUNCTION__, temp_register); - } - /* Preset return code. It will be changed later if things go okay. */ - rc = NO_ADAPTER_PRESENT; + goto err_exit; } - /* All F's is an empty slot or an invalid board */ - if (temp_register != 0xFFFFFFFF) { /* Check for a board in the slot */ - res_lists.io_head = ctrl->io_head; - res_lists.mem_head = ctrl->mem_head; - res_lists.p_mem_head = ctrl->p_mem_head; - res_lists.bus_head = ctrl->bus_head; - res_lists.irqs = NULL; - - rc = configure_new_device(ctrl, func, 0, &res_lists, 0, 0); - dbg("%s: back from configure_new_device\n", __FUNCTION__); - - ctrl->io_head = res_lists.io_head; - ctrl->mem_head = res_lists.mem_head; - ctrl->p_mem_head = res_lists.p_mem_head; - ctrl->bus_head = res_lists.bus_head; - - shpchp_resource_sort_and_combine(&(ctrl->mem_head)); - shpchp_resource_sort_and_combine(&(ctrl->p_mem_head)); - shpchp_resource_sort_and_combine(&(ctrl->io_head)); - shpchp_resource_sort_and_combine(&(ctrl->bus_head)); - - if (rc) { - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - /* turn off slot, turn on Amber LED, turn off Green LED */ - retval = p_slot->hpc_ops->slot_disable(p_slot); - if (retval) { - err("%s: Issue of Slot Enable command failed\n", __FUNCTION__); - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - return retval; - } - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - retval = p_slot->hpc_ops->check_cmd_status(ctrl); - if (retval) { - err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, retval); - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - return retval; - } + if (shpchp_configure_device(p_slot)) { + err("Cannot add device at 0x%x:0x%x\n", p_slot->bus, + p_slot->device); + goto err_exit; + } - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); + shpchp_save_slot_config(ctrl, func); - return(rc); - } - shpchp_save_slot_config(ctrl, func); + func->status = 0; + func->switch_save = 0x10; + func->is_a_board = 0x01; + func->pwr_save = 1; - func->status = 0; - func->switch_save = 0x10; - func->is_a_board = 0x01; - func->pwr_save = 1; + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); - /* Next, we will instantiate the linux pci_dev structures - * (with appropriate driver notification, if already present) - */ - index = 0; - do { - new_func = shpchp_slot_find(ctrl->slot_bus, func->device, index++); - if (new_func && !new_func->pci_dev) { - dbg("%s:call pci_hp_configure_dev\n", __FUNCTION__); - shpchp_configure_device(ctrl, new_func); - } - } while (new_func); + p_slot->hpc_ops->green_led_on(p_slot); - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); - p_slot->hpc_ops->green_led_on(p_slot); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); + return 0; +err_exit: + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + /* turn off slot, turn on Amber LED, turn off Green LED */ + rc = p_slot->hpc_ops->slot_disable(p_slot); + if (rc) { + err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); /* Done with exclusive hardware access */ up(&ctrl->crit_sect); + return rc; + } + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); - } else { - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - /* turn off slot, turn on Amber LED, turn off Green LED */ - rc = p_slot->hpc_ops->slot_disable(p_slot); - if (rc) { - err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - return rc; - } - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - rc = p_slot->hpc_ops->check_cmd_status(ctrl); - if (rc) { - err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc); - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - return rc; - } - + rc = p_slot->hpc_ops->check_cmd_status(ctrl); + if (rc) { + err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc); /* Done with exclusive hardware access */ up(&ctrl->crit_sect); - - return(rc); + return rc; } - return 0; + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + + return(rc); } @@ -1466,13 +766,9 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl) */ static u32 remove_board(struct pci_func *func, struct controller *ctrl) { - int index; - u8 skip = 0; u8 device; u8 hp_slot; u32 rc; - struc |