aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorrajesh.shah@intel.com <rajesh.shah@intel.com>2005-10-31 16:20:06 -0800
committerGreg Kroah-Hartman <gregkh@suse.de>2005-11-10 16:09:14 -0800
commit71b720c0f96145f5868c87591c286b290bc1a6af (patch)
tree797a97084494d99ec59670009242dc25174d3fb1 /drivers
parent24a4e377068d15424cd6a921d41352f295548037 (diff)
[PATCH] patch 1/8] pciehp: use the PCI core for hotplug resource management
This patch converts the pci express hotplug controller driver to use the PCI core for resource management. This eliminates a lot of duplicated code and integrates pciehp with 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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pci/hotplug/pciehp.h50
-rw-r--r--drivers/pci/hotplug/pciehp_core.c35
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c1563
-rw-r--r--drivers/pci/hotplug/pciehp_pci.c487
-rw-r--r--drivers/pci/hotplug/pciehprm_acpi.c840
-rw-r--r--drivers/pci/hotplug/pciehprm_nonacpi.c347
6 files changed, 85 insertions, 3237 deletions
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 061ead21ef1..e9480ddd5ab 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -59,14 +59,8 @@ struct pci_func {
u8 configured;
u8 switch_save;
u8 presence_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;
};
@@ -90,12 +84,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;
@@ -107,10 +95,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];
@@ -133,20 +117,6 @@ struct controller {
u8 cap_base;
};
-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 INT_BUTTON_IGNORE 0
#define INT_PRESENCE_ON 1
#define INT_PRESENCE_OFF 2
@@ -203,14 +173,12 @@ struct resource_lists {
#define msg_HPC_rev_error "Unsupported revision of the PCI hot plug controller found.\n"
#define msg_HPC_non_pcie "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 pciephd module. Upgrade to a newer version of pciehpd\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"
#define msg_button_ignore "PCI slot #%d - button press ignored. (action in progress...)\n"
/* controller functions */
-extern int pciehprm_find_available_resources (struct controller *ctrl);
extern int pciehp_event_start_thread (void);
extern void pciehp_event_stop_thread (void);
extern struct pci_func *pciehp_slot_create (unsigned char busnumber);
@@ -224,19 +192,12 @@ extern u8 pciehp_handle_presence_change (u8 hp_slot, void *inst_id);
extern u8 pciehp_handle_power_fault (u8 hp_slot, void *inst_id);
/* extern void long_delay (int delay); */
-/* resource functions */
-extern int pciehp_resource_sort_and_combine (struct pci_resource **head);
-
/* pci functions */
extern int pciehp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num);
/*extern int pciehp_get_bus_dev (struct controller *ctrl, u8 *bus_num, u8 *dev_num, struct slot *slot);*/
extern int pciehp_save_config (struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num);
-extern int pciehp_save_used_resources (struct controller *ctrl, struct pci_func * func, int flag);
extern int pciehp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot);
-extern void pciehp_destroy_board_resources (struct pci_func * func);
-extern int pciehp_return_board_resources (struct pci_func * func, struct resource_lists * resources);
-extern void pciehp_destroy_resource_list (struct resource_lists * resources);
-extern int pciehp_configure_device (struct controller* ctrl, struct pci_func* func);
+extern int pciehp_configure_device (struct slot *ctrl);
extern int pciehp_unconfigure_device (struct pci_func* func);
@@ -289,15 +250,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/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index cafc7eadcf8..190664e5adf 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -433,16 +433,8 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
goto err_out_free_ctrl_bus;
}
- /* Get IO, memory, and IRQ resources for new devices */
- rc = pciehprm_find_available_resources(ctrl);
- ctrl->add_support = !rc;
+ ctrl->add_support = 1;
- if (rc) {
- dbg("pciehprm_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) {
@@ -521,18 +513,6 @@ static int pcie_start_thread(void)
return retval;
}
-static inline void __exit
-free_pciehp_res(struct pci_resource *res)
-{
- struct pci_resource *tres;
-
- while (res) {
- tres = res;
- res = res->next;
- kfree(tres);
- }
-}
-
static void __exit unload_pciehpd(void)
{
struct pci_func *next;
@@ -546,11 +526,6 @@ static void __exit unload_pciehpd(void)
while (ctrl) {
cleanup_slots(ctrl);
- free_pciehp_res(ctrl->io_head);
- free_pciehp_res(ctrl->mem_head);
- free_pciehp_res(ctrl->p_mem_head);
- free_pciehp_res(ctrl->bus_head);
-
kfree (ctrl->pci_bus);
ctrl->hpc_ops->release_ctlr(ctrl);
@@ -564,11 +539,6 @@ static void __exit unload_pciehpd(void)
for (loop = 0; loop < 256; loop++) {
next = pciehp_slot_list[loop];
while (next != NULL) {
- free_pciehp_res(next->io_head);
- free_pciehp_res(next->mem_head);
- free_pciehp_res(next->p_mem_head);
- free_pciehp_res(next->bus_head);
-
TempSlot = next;
next = next->next;
kfree(TempSlot);
@@ -652,8 +622,7 @@ error_hpc_init:
if (retval) {
pciehprm_cleanup();
pciehp_event_stop_thread();
- } else
- pciehprm_print_pirt();
+ };
return retval;
}
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 898f6da6f0d..412783e0ef4 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -42,10 +42,6 @@
#include "pciehp.h"
#include "pciehprm.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) */
@@ -252,627 +248,6 @@ u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id)
return rc;
}
-
-/**
- * sort_by_size: sort nodes by their length, smallest first.
- *
- * @head: list to sort
- */
-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: return one unused resource node
- * @head: list to scan
- *
- */
-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 = pciehp_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(struct pci_resource), 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;
- } else {
- prevnode = *head;
- while (prevnode->next != node)
- prevnode = prevnode->next;
-
- prevnode->next = node->next;
- }
- node->next = NULL;
-
- return node;
-}
-
-
-/**
- * do_bridge_resource_split: return one unused resource node
- * @head: list to scan
- *
- */
-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 = pciehp_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 ( pciehp_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(struct pci_resource),
- 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(struct pci_resource),
- 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 (pciehp_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(struct pci_resource),
- 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(struct pci_resource),
- 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(struct pci_resource),
- 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 ( pciehp_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(struct pci_resource),
- 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(struct pci_resource),
- 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;
-}
-
-
-/*
- * pciehp_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 pciehp_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;
-}
-
-
/**
* pciehp_slot_create - Creates a node and adds it to the proper bus.
* @busnumber - bus where new node is to be located
@@ -926,7 +301,6 @@ static int slot_remove(struct pci_func * old_slot)
if (next == old_slot) {
pciehp_slot_list[old_slot->bus] = old_slot->next;
- pciehp_destroy_board_resources(old_slot);
kfree(old_slot);
return 0;
}
@@ -937,7 +311,6 @@ static int slot_remove(struct pci_func * old_slot)
if (next->next == old_slot) {
next->next = old_slot->next;
- pciehp_destroy_board_resources(old_slot);
kfree(old_slot);
return 0;
} else
@@ -1103,12 +476,9 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
static u32 board_added(struct pci_func * func, struct controller * ctrl)
{
u8 hp_slot;
- int index;
u32 temp_register = 0xFFFFFFFF;
u32 rc = 0;
- struct pci_func *new_func = NULL;
struct slot *p_slot;
- struct resource_lists res_lists;
p_slot = pciehp_find_slot(ctrl, func->device);
hp_slot = func->device - ctrl->slot_device_offset;
@@ -1162,89 +532,43 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl)
dbg("%s: temp register set to %x by power fault\n", __FUNCTION__, temp_register);
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;
-
- pciehp_resource_sort_and_combine(&(ctrl->mem_head));
- pciehp_resource_sort_and_combine(&(ctrl->p_mem_head));
- pciehp_resource_sort_and_combine(&(ctrl->io_head));
- pciehp_resource_sort_and_combine(&(ctrl->bus_head));
+ rc = pciehp_configure_device(p_slot);
+ if (rc) {
+ err("Cannot add device 0x%x:%x\n", p_slot->bus,
+ p_slot->device);
+ goto err_exit;
+ }
- if (rc) {
- set_slot_off(ctrl, p_slot);
- return rc;
- }
- pciehp_save_slot_config(ctrl, func);
+ pciehp_save_slot_config(ctrl, func);
+ func->status = 0;
+ func->switch_save = 0x10;
+ func->is_a_board = 0x01;
- func->status = 0;
- func->switch_save = 0x10;
- func->is_a_board = 0x01;
+ /*
+ * Some PCI Express root ports require fixup after hot-plug operation.
+ */
+ if (pcie_mch_quirk)
+ pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
+ if (PWR_LED(ctrl->ctrlcap)) {
+ /* 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 = pciehp_slot_find(ctrl->slot_bus, func->device, index++);
- if (new_func && !new_func->pci_dev) {
- dbg("%s:call pci_hp_configure_dev, func %x\n",
- __FUNCTION__, index);
- pciehp_configure_device(ctrl, new_func);
- }
- } while (new_func);
-
- /*
- * Some PCI Express root ports require fixup after hot-plug operation.
- */
- if (pcie_mch_quirk)
- pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
-
- if (PWR_LED(ctrl->ctrlcap)) {
- /* Wait for exclusive access to hardware */
- down(&ctrl->crit_sect);
-
- p_slot->hpc_ops->green_led_on(p_slot);
+ p_slot->hpc_ops->green_led_on(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
+ /* Wait for the command to complete */
+ wait_for_ctrl_irq (ctrl);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- }
- } else {
- set_slot_off(ctrl, p_slot);
- return -1;
- }
+ /* Done with exclusive hardware access */
+ up(&ctrl->crit_sect);
+ }
return 0;
+
+err_exit:
+ set_slot_off(ctrl, p_slot);
+ return -1;
}
@@ -1254,13 +578,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;
- struct resource_lists res_lists;
- struct pci_func *temp_func;
struct slot *p_slot;
if (func == NULL)
@@ -1276,27 +596,6 @@ static u32 remove_board(struct pci_func *func, struct controller *ctrl)
dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
- if ((ctrl->add_support) &&
- !(func->bus_head || func->mem_head || func->p_mem_head || func->io_head)) {
- /* Here we check to see if we've saved any of the board's
- * resources already. If so, we'll skip the attempt to
- * determine what's being used.
- */
- index = 0;
-
- temp_func = func;
-
- while ((temp_func = pciehp_slot_find(temp_func->bus, temp_func->device, index++))) {
- if (temp_func->bus_head || temp_func->mem_head
- || temp_func->p_mem_head || temp_func->io_head) {
- skip = 1;
- break;
- }
- }
-
- if (!skip)
- rc = pciehp_save_used_resources(ctrl, func, DISABLE_CARD);
- }
/* Change status to shutdown */
if (func->is_a_board)
func->status = 0x01;
@@ -1330,26 +629,6 @@ static u32 remove_board(struct pci_func *func, struct controller *ctrl)
if (ctrl->add_support) {
while (func) {
- 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;
-
- dbg("Returning resources to ctlr lists for (B/D/F) = (%#x/%#x/%#x)\n",
- func->bus, func->device, func->function);
-
- pciehp_return_board_resources(func, &res_lists);
-
- 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;
-
- pciehp_resource_sort_and_combine(&(ctrl->mem_head));
- pciehp_resource_sort_and_combine(&(ctrl->p_mem_head));
- pciehp_resource_sort_and_combine(&(ctrl->io_head));
- pciehp_resource_sort_and_combine(&(ctrl->bus_head));
-
if (is_bridge(func)) {
dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n",
ctrl->seg, func->bus, func->device, func->function);
@@ -1918,787 +1197,3 @@ int pciehp_disable_slot(struct slot *p_slot)
return rc;
}
-
-/**
- * configure_new_device - Configures the PCI header information of one board.
- *
- * @ctrl: pointer to controller structure
- * @func: pointer to function structure
- * @behind_bridge: 1 if this is a recursive call, 0 if not
- * @resources: pointer to set of resource lists
- *
- * Returns 0 if success
- *
- */
-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)
-{
- u8 temp_byte, function, max_functions, stop_it;
- int rc;
- u32 ID;
- struct pci_func *new_slot;
- struct pci_bus lpci_bus, *pci_bus;
- int index;
-
- new_slot = func;
-
- dbg("%s\n", __FUNCTION__);
- memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
- pci_bus = &lpci_bus;
- pci_bus->number = func->bus;
-
- /* Check for Multi-function device */
- rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(func->device, func->function), 0x0E, &temp_byte);
- if (rc) {
- dbg("%s: rc = %d\n", __FUNCTION__, rc);
- return rc;
- }
-
- if (temp_byte & 0x80) /* Multi-function device */
- max_functions = 8;
- else
- max_functions = 1;
-
- function = 0;
-
- do {
- rc = configure_new_function(ctrl, new_slot, behind_bridge,
- resources, bridge_bus, bridge_dev);
-
- if (rc) {
- dbg("configure_new_function failed: %d\n", rc);
- index = 0;
-
- while (new_slot) {
- new_slot = pciehp_slot_find(new_slot->bus,
- new_slot->device, index++);