}
-/*
- * sort_by_size
- *
- * Sorts nodes on the list by their length.
- * Smallest first.
+/**
+ * sort_by_size: sort nodes by their length, smallest first.
*
+ * @head: list to sort
*/
static int sort_by_size(struct pci_resource **head)
{
int out_of_order = 1;
if (!(*head))
- return(1);
+ return 1;
if (!((*head)->next))
- return(0);
+ return 0;
while (out_of_order) {
out_of_order = 0;
}
} /* End of out_of_order loop */
- return(0);
+ return 0;
}
int out_of_order = 1;
if (!(*head))
- return(1);
+ return 1;
if (!((*head)->next))
- return(0);
+ return 0;
while (out_of_order) {
out_of_order = 0;
}
} /* End of out_of_order loop */
- return(0);
+ return 0;
}
-/*
- * do_pre_bridge_resource_split
- *
- * Returns zero or one node of resources that aren't in use
+/**
+ * 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)
+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;
dbg("do_pre_bridge_resource_split\n");
if (!(*head) || !(*orig_head))
- return(NULL);
+ return NULL;
rc = pciehp_resource_sort_and_combine(head);
if (rc)
- return(NULL);
+ return NULL;
if ((*head)->base != (*orig_head)->base)
- return(NULL);
+ return NULL;
if ((*head)->length == (*orig_head)->length)
- return(NULL);
+ return NULL;
/* If we got here, there the bridge requires some of the resource, but
/* this one isn't an aligned length, so we'll make a new entry
* and split it up.
*/
- split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+ split_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
if (!split_node)
- return(NULL);
+ return NULL;
temp_dword = (node->length | (alignment-1)) + 1 - alignment;
split_node->next = node;
}
- if (node->length < alignment) {
- return(NULL);
- }
+ 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;
}
+ node->next = NULL;
- return(node);
+ return node;
}
-/*
- * do_bridge_resource_split
- *
- * Returns zero or one node of resources that aren't in use
+/**
+ * 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)
+static struct pci_resource *
+do_bridge_resource_split(struct pci_resource **head, u32 alignment)
{
struct pci_resource *prevnode = NULL;
struct pci_resource *node;
u32 temp_dword;
if (!(*head))
- return(NULL);
+ return NULL;
rc = pciehp_resource_sort_and_combine(head);
if (rc)
- return(NULL);
+ return NULL;
node = *head;
if (node->length < alignment) {
kfree(node);
- return(NULL);
+ return NULL;
}
if (node->base & (alignment - 1)) {
temp_dword = (node->base | (alignment-1)) + 1;
if ((node->length - (temp_dword - node->base)) < alignment) {
kfree(node);
- return(NULL);
+ return NULL;
}
node->length -= (temp_dword - node->base);
if (node->length & (alignment - 1)) {
/* There's stuff in use after this node */
kfree(node);
- return(NULL);
+ return NULL;
}
- return(node);
+ return node;
}
*
* size must be a power of two.
*/
-static struct pci_resource *get_io_resource (struct pci_resource **head, u32 size)
+static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size)
{
struct pci_resource *prevnode;
struct pci_resource *node;
u32 temp_dword;
if (!(*head))
- return(NULL);
+ return NULL;
if ( pciehp_resource_sort_and_combine(head) )
- return(NULL);
+ return NULL;
if ( sort_by_size(head) )
- return(NULL);
+ return NULL;
for (node = *head; node; node = node->next) {
if (node->length < size)
if ((node->length - (temp_dword - node->base)) < size)
continue;
- split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+ split_node = kmalloc(sizeof(struct pci_resource),
+ GFP_KERNEL);
if (!split_node)
- return(NULL);
+ return NULL;
split_node->base = node->base;
split_node->length = temp_dword - node->base;
if (node->length > size) {
/* this one is longer than we need
so we'll make a new entry and split it up */
- split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+ split_node = kmalloc(sizeof(struct pci_resource),
+ GFP_KERNEL);
if (!split_node)
- return(NULL);
+ return NULL;
split_node->base = node->base + size;
split_node->length = node->length - size;
break;
}
- return(node);
+ return node;
}
* 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)
+static struct pci_resource *get_max_resource(struct pci_resource **head, u32 size)
{
struct pci_resource *max;
struct pci_resource *temp;
int i;
if (!(*head))
- return(NULL);
+ return NULL;
if (pciehp_resource_sort_and_combine(head))
- return(NULL);
+ return NULL;
if (sort_by_max_size(head))
- return(NULL);
+ return NULL;
for (max = *head;max; max = max->next) {
if ((max->length - (temp_dword - max->base)) < size)
continue;
- split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+ split_node = kmalloc(sizeof(struct pci_resource),
+ GFP_KERNEL);
if (!split_node)
- return(NULL);
+ return NULL;
split_node->base = max->base;
split_node->length = temp_dword - max->base;
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 = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+ split_node = kmalloc(sizeof(struct pci_resource),
+ GFP_KERNEL);
if (!split_node)
- return(NULL);
+ return NULL;
temp_dword = ((max->base + max->length) & ~(size - 1));
split_node->base = temp_dword;
split_node->length = max->length + max->base
for ( i = 0; max_size[i] > size; i++) {
if (max->length > max_size[i]) {
- split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+ split_node = kmalloc(sizeof(struct pci_resource),
+ GFP_KERNEL);
if (!split_node)
- break; /* return (NULL); */
+ break; /* return NULL; */
split_node->base = max->base + max_size[i];
split_node->length = max->length - max_size[i];
max->length = max_size[i];
}
max->next = NULL;
- return(max);
+ return max;
}
/* If we get here, we couldn't find one */
- return(NULL);
+ return NULL;
}
*
* size must be a power of two.
*/
-static struct pci_resource *get_resource (struct pci_resource **head, u32 size)
+static struct pci_resource *get_resource(struct pci_resource **head, u32 size)
{
struct pci_resource *prevnode;
struct pci_resource *node;
u32 temp_dword;
if (!(*head))
- return(NULL);
+ return NULL;
if ( pciehp_resource_sort_and_combine(head) )
- return(NULL);
+ return NULL;
if ( sort_by_size(head) )
- return(NULL);
+ return NULL;
for (node = *head; node; node = node->next) {
dbg("%s: req_size =0x%x node=%p, base=0x%x, length=0x%x\n",
if ((node->length - (temp_dword - node->base)) < size)
continue;
- split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+ split_node = kmalloc(sizeof(struct pci_resource),
+ GFP_KERNEL);
if (!split_node)
- return(NULL);
+ return NULL;
split_node->base = node->base;
split_node->length = temp_dword - node->base;
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 = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+ split_node = kmalloc(sizeof(struct pci_resource),
+ GFP_KERNEL);
if (!split_node)
- return(NULL);
+ return NULL;
split_node->base = node->base + size;
split_node->length = node->length - size;
/* Stop looping */
break;
}
- return(node);
+ return node;
}
dbg("%s: head = %p, *head = %p\n", __FUNCTION__, head, *head);
if (!(*head))
- return(1);
+ return 1;
dbg("*head->next = %p\n",(*head)->next);
if (!(*head)->next)
- return(0); /* only one item on the list, already sorted! */
+ 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);
node1 = node1->next;
}
- return(0);
+ return 0;
}
struct pci_func *new_slot;
struct pci_func *next;
dbg("%s: busnumber %x\n", __FUNCTION__, busnumber);
- new_slot = (struct pci_func *) kmalloc(sizeof(struct pci_func), GFP_KERNEL);
+ new_slot = kmalloc(sizeof(struct pci_func), GFP_KERNEL);
- if (new_slot == NULL) {
- return(new_slot);
- }
+ if (new_slot == NULL)
+ return new_slot;
memset(new_slot, 0, sizeof(struct pci_func));
next = next->next;
next->next = new_slot;
}
- return(new_slot);
+ return new_slot;
}
-/*
+/**
* slot_remove - Removes a node from the linked list of slots.
* @old_slot: slot to remove
*
struct pci_func *next;
if (old_slot == NULL)
- return(1);
+ return 1;
next = pciehp_slot_list[old_slot->bus];
- if (next == NULL) {
- return(1);
- }
+ if (next == NULL)
+ return 1;
if (next == old_slot) {
pciehp_slot_list[old_slot->bus] = old_slot->next;
pciehp_destroy_board_resources(old_slot);
kfree(old_slot);
- return(0);
+ return 0;
}
while ((next->next != old_slot) && (next->next != NULL)) {
next->next = old_slot->next;
pciehp_destroy_board_resources(old_slot);
kfree(old_slot);
- return(0);
+ return 0;
} else
- return(2);
+ return 2;
}
struct pci_func *next;
if (bridge == NULL)
- return(1);
+ return 1;
secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF;
subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF;
next = pciehp_slot_list[bridge->bus];
if (next == NULL) {
- return(1);
+ return 1;
}
if (next == bridge) {
pciehp_slot_list[bridge->bus] = bridge->next;
kfree(bridge);
- return(0);
+ return 0;
}
while ((next->next != bridge) && (next->next != NULL)) {
if (next->next == bridge) {
next->next = bridge->next;
kfree(bridge);
- return(0);
+ return 0;
} else
- return(2);
+ return 2;
}
dbg("%s: func == NULL\n", __FUNCTION__);
if ((func == NULL) || ((func->device == device) && (index == 0)))
- return(func);
+ return func;
if (func->device == device)
found++;
if ((found == index) || (func->function == index)) {
dbg("%s: Found bus %x dev %x func %x\n", __FUNCTION__,
func->bus, func->device, func->function);
- return(func);
+ return func;
}
}
- return(NULL);
+ return NULL;
}
static int is_bridge(struct pci_func * func)
/* Done with exclusive hardware access */
up(&ctrl->crit_sect);
- return(rc);
+ return rc;
}
pciehp_save_slot_config(ctrl, func);
/* Done with exclusive hardware access */
up(&ctrl->crit_sect);
- return(rc);
+ return rc;
}
return 0;
}
struct slot *p_slot;
if (func == NULL)
- return(1);
+ return 1;
if (pciehp_unconfigure_device(func))
- return(1);
+ return 1;
device = func->device;
func = pciehp_slot_create(ctrl->slot_bus);
if (func == NULL) {
- return(1);
+ return 1;
}
func->bus = ctrl->slot_bus;
}
-static void pushbutton_helper_thread (unsigned long data)
+static void pushbutton_helper_thread(unsigned long data)
{
pushbutton_pending = data;
}
+/**
+ * pciehp_pushbutton_thread
+ *
+ * Scheduled procedure to handle blocking stuff for the pushbuttons
+ * Handles all pending events and exits.
+ *
+ */
+static void pciehp_pushbutton_thread(unsigned long slot)
+{
+ struct slot *p_slot = (struct slot *) slot;
+ u8 getstatus;
+ int rc;
+
+ pushbutton_pending = 0;
+
+ if (!p_slot) {
+ dbg("%s: Error! slot NULL\n", __FUNCTION__);
+ return;
+ }
+
+ p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+ if (getstatus) {
+ p_slot->state = POWEROFF_STATE;
+ dbg("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
+
+ if (pciehp_disable_slot(p_slot)) {
+ /* Wait for exclusive access to hardware */
+ down(&p_slot->ctrl->crit_sect);
+
+ /* Turn on the Attention LED */
+ rc = p_slot->hpc_ops->set_attention_status(p_slot, 1);
+ if (rc) {
+ err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__);
+ return;
+ }
+
+ /* Wait for the command to complete */
+ wait_for_ctrl_irq (p_slot->ctrl);
+
+ /* Done with exclusive hardware access */
+ up(&p_slot->ctrl->crit_sect);
+ }
+ p_slot->state = STATIC_STATE;
+ } else {
+ p_slot->state = POWERON_STATE;
+ dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
+
+ if (pciehp_enable_slot(p_slot)) {
+ /* Wait for exclusive access to hardware */
+ down(&p_slot->ctrl->crit_sect);
+
+ /* Turn off the green LED */
+ rc = p_slot->hpc_ops->set_attention_status(p_slot, 1);
+ if (rc) {
+ err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__);
+ return;
+ }
+ /* Wait for the command to complete */
+ wait_for_ctrl_irq (p_slot->ctrl);
+
+ p_slot->hpc_ops->green_led_off(p_slot);
+
+ /* Wait for the command to complete */
+ wait_for_ctrl_irq (p_slot->ctrl);
+
+ /* Done with exclusive hardware access */
+ up(&p_slot->ctrl->crit_sect);
+ }
+ p_slot->state = STATIC_STATE;
+ }
+
+ return;
+}
+
+
/* this is the main worker thread */
static int event_thread(void* data)
{
return 0;
}
-int pciehp_event_start_thread (void)
+int pciehp_event_start_thread(void)
{
int pid;
}
-void pciehp_event_stop_thread (void)
+void pciehp_event_stop_thread(void)
{
event_finished = 1;
dbg("event_thread finish command given\n");
}
-static int update_slot_info (struct slot *slot)
+static int update_slot_info(struct slot *slot)
{
struct hotplug_slot_info *info;
/* char buffer[SLOT_NAME_SIZE]; */
int result;
- info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
+ info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
}
} /* End of FOR loop */
}
-
- return;
}
-/**
- * pciehp_pushbutton_thread
- *
- * Scheduled procedure to handle blocking stuff for the pushbuttons
- * Handles all pending events and exits.
- *
- */
-void pciehp_pushbutton_thread (unsigned long slot)
-{
- struct slot *p_slot = (struct slot *) slot;
- u8 getstatus;
- int rc;
-
- pushbutton_pending = 0;
-
- if (!p_slot) {
- dbg("%s: Error! slot NULL\n", __FUNCTION__);
- return;
- }
-
- p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
- if (getstatus) {
- p_slot->state = POWEROFF_STATE;
- dbg("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
-
- if (pciehp_disable_slot(p_slot)) {
- /* Wait for exclusive access to hardware */
- down(&p_slot->ctrl->crit_sect);
-
- /* Turn on the Attention LED */
- rc = p_slot->hpc_ops->set_attention_status(p_slot, 1);
- if (rc) {
- err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__);
- return;
- }
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (p_slot->ctrl);
-
- /* Done with exclusive hardware access */
- up(&p_slot->ctrl->crit_sect);
- }
- p_slot->state = STATIC_STATE;
- } else {
- p_slot->state = POWERON_STATE;
- dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
-
- if (pciehp_enable_slot(p_slot)) {
- /* Wait for exclusive access to hardware */
- down(&p_slot->ctrl->crit_sect);
-
- /* Turn off the green LED */
- rc = p_slot->hpc_ops->set_attention_status(p_slot, 1);
- if (rc) {
- err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__);
- return;
- }
- /* Wait for the command to complete */
- wait_for_ctrl_irq (p_slot->ctrl);
-
- p_slot->hpc_ops->green_led_off(p_slot);
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (p_slot->ctrl);
-
- /* Done with exclusive hardware access */
- up(&p_slot->ctrl->crit_sect);
- }
- p_slot->state = STATIC_STATE;
- }
-
- return;
-}
-
-
-int pciehp_enable_slot (struct slot *p_slot)
+int pciehp_enable_slot(struct slot *p_slot)
{
u8 getstatus = 0;
int rc;
func = pciehp_slot_find(p_slot->bus, p_slot->device, 0);
if (!func) {
dbg("%s: Error! slot NULL\n", __FUNCTION__);
- return (1);
+ return 1;
}
/* Check to see if (latch closed, card present, power off) */
if (rc || !getstatus) {
info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
- return (0);
+ return 0;
}
rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (rc || getstatus) {
info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
- return (0);
+ return 0;
}
rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (rc || getstatus) {
info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
- return (0);
+ return 0;
}
up(&p_slot->ctrl->crit_sect);
func = pciehp_slot_create(p_slot->bus);
if (func == NULL)
- return (1);
+ return 1;
func->bus = p_slot->bus;
func->device = p_slot->device;
/* Setup slot structure with entry for empty slot */
func = pciehp_slot_create(p_slot->bus);
if (func == NULL)
- return (1); /* Out of memory */
+ return 1; /* Out of memory */
func->bus = p_slot->bus;
func->device = p_slot->device;
}
-int pciehp_disable_slot (struct slot *p_slot)
+int pciehp_disable_slot(struct slot *p_slot)
{
u8 class_code, header_type, BCR;
u8 index = 0;
struct pci_func *func;
if (!p_slot->ctrl)
- return (1);
+ return 1;
/* Check to see if (latch closed, card present, power on) */
down(&p_slot->ctrl->crit_sect);
if (ret || !getstatus) {
info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
- return (0);
+ return 0;
}
ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (ret || getstatus) {
info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
- return (0);
+ return 0;
}
ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (ret || !getstatus) {
info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect);
- return (0);
+ return 0;
}
up(&p_slot->ctrl->crit_sect);
if (p_slot)
update_slot_info(p_slot);
- return(rc);
+ return rc;
}
* Returns 0 if success
*
*/
-static u32 configure_new_device (struct controller * ctrl, struct pci_func * func,
+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;
function = 0;
do {
- rc = configure_new_function(ctrl, new_slot, behind_bridge, resources, bridge_bus, bridge_dev);
+ rc = configure_new_function(ctrl, new_slot, behind_bridge,
+ resources, bridge_bus, bridge_dev);
if (rc) {
- dbg("configure_new_function failed %d\n",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++);
+ new_slot = pciehp_slot_find(new_slot->bus,
+ new_slot->device, index++);
if (new_slot)
- pciehp_return_board_resources(new_slot, resources);
+ pciehp_return_board_resources(new_slot,
+ resources);
}
- return(rc);
+ return rc;
}
function++;
if (new_slot == NULL) {
/* Out of memory */
- return(1);
+ return 1;
}
new_slot->bus = func->bus;
}
} while (function < max_functions);
- dbg("returning from configure_new_device\n");
+ dbg("returning from %s\n", __FUNCTION__);
return 0;
}
-
/*
* Configuration logic that involves the hotplug data structures and
* their bookkeeping
*/
-
/**
- * configure_new_function - Configures the PCI header information of one device
- *
- * @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
- *
- * Calls itself recursively for bridged devices.
- * Returns 0 if success
- *
+ * configure_bridge: fill bridge's registers, either configure or disable it.
*/
-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 int
+configure_bridge(struct pci_bus *pci_bus, unsigned int devfn,
+ struct pci_resource *mem_node,
+ struct pci_resource **hold_mem_node,
+ int base_addr, int limit_addr)
+{
+ u16 temp_word;
+ u32 rc;
+
+ if (mem_node) {
+ memcpy(*hold_mem_node, mem_node, sizeof(struct pci_resource));
+ mem_node->next = NULL;
+
+ /* set Mem base and Limit registers */
+ RES_CHECK(mem_node->base, 16);
+ temp_word = (u16)(mem_node->base >> 16);
+ rc = pci_bus_write_config_word(pci_bus, devfn, base_addr, temp_word);
+
+ RES_CHECK(mem_node->base + mem_node->length - 1, 16);
+ temp_word = (u16)((mem_node->base + mem_node->length - 1) >> 16);
+ rc = pci_bus_write_config_word(pci_bus, devfn, limit_addr, temp_word);
+ } else {
+ temp_word = 0xFFFF;
+ rc = pci_bus_write_config_word(pci_bus, devfn, base_addr, temp_word);
+
+ temp_word = 0x0000;
+ rc = pci_bus_write_config_word(pci_bus, devfn, limit_addr, temp_word);
+
+ kfree(*hold_mem_node);
+ *hold_mem_node = NULL;
+ }
+ return rc;
+}
+
+static int
+configure_new_bridge(struct controller *ctrl, struct pci_func *func,
+ u8 behind_bridge, struct resource_lists *resources,
+ struct pci_bus *pci_bus)
{
int cloop;
u8 temp_byte;
u8 device;
- u8 class_code;
u16 temp_word;
u32 rc;
- u32 temp_register;
- u32 base;
u32 ID;
unsigned int devfn;
struct pci_resource *mem_node;
struct pci_resource *hold_bus_node;
struct irq_mapping irqs;
struct pci_func *new_slot;
- struct pci_bus lpci_bus, *pci_bus;
struct resource_lists temp_resources;
- memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
- pci_bus = &lpci_bus;
- pci_bus->number = func->bus;
devfn = PCI_DEVFN(func->device, func->function);
- /* Check for Bridge */
- rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &temp_byte);
+ /* set Primary bus */
+ dbg("set Primary bus = 0x%x\n", func->bus);
+ rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func->bus);
if (rc)
return rc;
- dbg("%s: bus %x dev %x func %x temp_byte = %x\n", __FUNCTION__,
- func->bus, func->device, func->function, temp_byte);
- if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */
- /* set Primary bus */
- dbg("set Primary bus = 0x%x\n", func->bus);
- rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func->bus);
- if (rc)
- return rc;
-
- /* find range of busses to use */
- bus_node = get_max_resource(&resources->bus_head, 1L);
-
- /* If we don't have any busses to allocate, we can't continue */
- if (!bus_node) {
- err("Got NO bus resource to use\n");
- return -ENOMEM;
- }
- dbg("Got ranges of buses to use: base:len=0x%x:%x\n", bus_node->base, bus_node->length);
+ /* find range of busses to use */
+ bus_node = get_max_resource(&resources->bus_head, 1L);
- /* set Secondary bus */
- dbg("set Secondary bus = 0x%x\n", temp_byte);
- dbg("func->bus %x\n", func->bus);
-
- temp_byte = (u8)bus_node->base;
- dbg("set Secondary bus = 0x%x\n", temp_byte);
- rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, temp_byte);
- if (rc)
- return rc;
-
- /* set subordinate bus */
- temp_byte = (u8)(bus_node->base + bus_node->length - 1);
- dbg("set subordinate bus = 0x%x\n", temp_byte);
- rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte);
- if (rc)
- return rc;
+ /* If we don't have any busses to allocate, we can't continue */
+ if (!bus_node) {
+ err("Got NO bus resource to use\n");
+ return -ENOMEM;
+ }
+ dbg("Got ranges of buses to use: base:len=0x%x:%x\n", bus_node->base, bus_node->length);
- /* Set HP parameters (Cache Line Size, Latency Timer) */
- rc = pciehprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_BRIDGE);
- if (rc)
- return rc;
+ /* set Secondary bus */
+ temp_byte = (u8)bus_node->base;
+ dbg("set Secondary bus = 0x%x\n", temp_byte);
+ rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, temp_byte);
+ if (rc)
+ return rc;
- /* Setup the IO, memory, and prefetchable windows */
+ /* set subordinate bus */
+ temp_byte = (u8)(bus_node->base + bus_node->length - 1);
+ dbg("set subordinate bus = 0x%x\n", temp_byte);
+ rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte);
+ if (rc)
+ return rc;
- io_node = get_max_resource(&(resources->io_head), 0x1000L);
- if (io_node) {
- dbg("io_node(base, len, next) (%x, %x, %p)\n", io_node->base, io_node->length, io_node->next);
- }
+ /* Set HP parameters (Cache Line Size, Latency Timer) */
+ rc = pciehprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_BRIDGE);
+ if (rc)
+ return rc;
- mem_node = get_max_resource(&(resources->mem_head), 0x100000L);
- if (mem_node) {
- dbg("mem_node(base, len, next) (%x, %x, %p)\n", mem_node->base, mem_node->length, mem_node->next);
- }
+ /* Setup the IO, memory, and prefetchable windows */
- if (resources->p_mem_head)
- p_mem_node = get_max_resource(&(resources->p_mem_head), 0x100000L);
- else {
- /*
- * In some platform implementation, MEM and PMEM are not
- * distinguished, and hence ACPI _CRS has only MEM entries
- * for both MEM and PMEM.
- */
- dbg("using MEM for PMEM\n");
- p_mem_node = get_max_resource(&(resources->mem_head), 0x100000L);
- }
- if (p_mem_node) {
- dbg("p_mem_node(base, len, next) (%x, %x, %p)\n", p_mem_node->base, p_mem_node->length, p_mem_node->next);
- }
+ io_node = get_max_resource(&(resources->io_head), 0x1000L);
+ if (io_node) {
+ dbg("io_node(base, len, next) (%x, %x, %p)\n", io_node->base,
+ io_node->length, io_node->next);
+ }
- /* set up the IRQ info */
- if (!resources->irqs) {
- irqs.barber_pole = 0;
- irqs.interrupt[0] = 0;
- irqs.interrupt[1] = 0;
- irqs.interrupt[2] = 0;
- irqs.interrupt[3] = 0;
- irqs.valid_INT = 0;
- } else {
- irqs.barber_pole = resources->irqs->barber_pole;
- irqs.interrupt[0] = resources->irqs->interrupt[0];
- irqs.interrupt[1] = resources->irqs->interrupt[1];
- irqs.interrupt[2] = resources->irqs->interrupt[2];
- irqs.interrupt[3] = resources->irqs->interrupt[3];
- irqs.valid_INT = resources->irqs->valid_INT;
- }
+ mem_node = get_max_resource(&(resources->mem_head), 0x100000L);
+ if (mem_node) {
+ dbg("mem_node(base, len, next) (%x, %x, %p)\n", mem_node->base,
+ mem_node->length, mem_node->next);
+ }
- /* set up resource lists that are now aligned on top and bottom
- * for anything behind the bridge.
- */
- temp_resources.bus_head = bus_node;
- temp_resources.io_head = io_node;
- temp_resources.mem_head = mem_node;
- temp_resources.p_mem_head = p_mem_node;
- temp_resources.irqs = &irqs;
-
- /* Make copies of the nodes we are going to pass down so that
- * if there is a problem,we can just use these to free resources
+ if (resources->p_mem_head)
+ p_mem_node = get_max_resource(&(resources->p_mem_head), 0x100000L);
+ else {
+ /*
+ * In some platform implementation, MEM and PMEM are not
+ * distinguished, and hence ACPI _CRS has only MEM entries
+ * for both MEM and PMEM.
*/
- hold_bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
- hold_IO_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
- hold_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
- hold_p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
-
- if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) {
- if (hold_bus_node)
- kfree(hold_bus_node);
- if (hold_IO_node)
- kfree(hold_IO_node);
- if (hold_mem_node)
- kfree(hold_mem_node);
- if (hold_p_mem_node)
- kfree(hold_p_mem_node);
-
- return(1);
- }
-
- memcpy(hold_bus_node, bus_node, sizeof(struct pci_resource));
+ dbg("using MEM for PMEM\n");
+ p_mem_node = get_max_resource(&(resources->mem_head), 0x100000L);
+ }
+ if (p_mem_node) {
+ dbg("p_mem_node(base, len, next) (%x, %x, %p)\n", p_mem_node->base,
+ p_mem_node->length, p_mem_node->next);
+ }
- bus_node->base += 1;
- bus_node->length -= 1;
- bus_node->next = NULL;
+ /* set up the IRQ info */
+ if (!resources->irqs) {
+ irqs.barber_pole = 0;
+ irqs.interrupt[0] = 0;
+ irqs.interrupt[1] = 0;
+ irqs.interrupt[2] = 0;
+ irqs.interrupt[3] = 0;
+ irqs.valid_INT = 0;
+ } else {
+ irqs.barber_pole = resources->irqs->barber_pole;
+ irqs.interrupt[0] = resources->irqs->interrupt[0];
+ irqs.interrupt[1] = resources->irqs->interrupt[1];
+ irqs.interrupt[2] = resources->irqs->interrupt[2];
+ irqs.interrupt[3] = resources->irqs->interrupt[3];
+ irqs.valid_INT = resources->irqs->valid_INT;
+ }
- /* If we have IO resources copy them and fill in the bridge's
- * IO range registers
- */
- if (io_node) {
- memcpy(hold_IO_node, io_node, sizeof(struct pci_resource));
- io_node->next = NULL;
+ /* set up resource lists that are now aligned on top and bottom
+ * for anything behind the bridge.
+ */
+ temp_resources.bus_head = bus_node;
+ temp_resources.io_head = io_node;
+ temp_resources.mem_head = mem_node;
+ temp_resources.p_mem_head = p_mem_node;
+ temp_resources.irqs = &irqs;
+
+ /* Make copies of the nodes we are going to pass down so that
+ * if there is a problem,we can just use these to free resources
+ */
+ hold_bus_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+ hold_IO_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+ hold_mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+ hold_p_mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
- /* set IO base and Limit registers */
- RES_CHECK(io_node->base, 8);
- temp_byte = (u8)(io_node->base >> 8);
- rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte);
+ if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) {
+ kfree(hold_bus_node);
+ kfree(hold_IO_node);
+ kfree(hold_mem_node);
+ kfree(hold_p_mem_node);
- RES_CHECK(io_node->base + io_node->length - 1, 8);
- temp_byte = (u8)((io_node->base + io_node->length - 1) >> 8);
- rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
- } else {
- kfree(hold_IO_node);
- hold_IO_node = NULL;
- }
+ return 1;
+ }
- /* If we have memory resources copy them and fill in the bridge's
- * memory range registers. Otherwise, fill in the range
- * registers with values that disable them.
- */
- if (mem_node) {
- memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource));
- mem_node->next = NULL;
+ memcpy(hold_bus_node, bus_node, sizeof(struct pci_resource));
- /* set Mem base and Limit registers */
- RES_CHECK(mem_node->base, 16);
- temp_word = (u32)(mem_node->base >> 16);
- rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
+ bus_node->base += 1;
+ bus_node->length -= 1;
+ bus_node->next = NULL;
- RES_CHECK(mem_node->base + mem_node->length - 1, 16);
- temp_word = (u32)((mem_node->base + mem_node->length - 1) >> 16);
- rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
- } else {
- temp_word = 0xFFFF;
- rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
+ /* If we have IO resources copy them and fill in the bridge's
+ * IO range registers
+ */
+ if (io_node) {
+ memcpy(hold_IO_node, io_node, sizeof(struct pci_resource));
+ io_node->next = NULL;
+
+ /* set IO base and Limit registers */
+ RES_CHECK(io_node->base, 8);
+ temp_byte = (u8)(io_node->base >> 8);
+ rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte);
+
+ RES_CHECK(io_node->base + io_node->length - 1, 8);
+ temp_byte = (u8)((io_node->base + io_node->length - 1) >> 8);
+ rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
+ } else {
+ kfree(hold_IO_node);
+ hold_IO_node = NULL;
+ }
- temp_word = 0x0000;
- rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+ /* If we have memory resources copy them and fill in the bridge's
+ * memory range registers. Otherwise, fill in the range
+ * registers with values that disable them.
+ */
+ rc = configure_bridge(pci_bus, devfn, mem_node, &hold_mem_node,
+ PCI_MEMORY_BASE, PCI_MEMORY_LIMIT);
- kfree(hold_mem_node);
- hold_mem_node = NULL;
- }
+ /* If we have prefetchable memory resources copy them and
+ * fill in the bridge's memory range registers. Otherwise,
+ * fill in the range registers with values that disable them.
+ */
+ rc = configure_bridge(pci_bus, devfn, p_mem_node, &hold_p_mem_node,
+ PCI_PREF_MEMORY_BASE, PCI_PREF_MEMORY_LIMIT);
- /* If we have prefetchable memory resources copy them and
- * fill in the bridge's memory range registers. Otherwise,
- * fill in the range registers with values that disable them.
- */
- if (p_mem_node) {
- memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource));
- p_mem_node->next = NULL;
+ /* Adjust this to compensate for extra adjustment in first loop */
+ irqs.barber_pole--;
- /* set Pre Mem base and Limit registers */
- RES_CHECK(p_mem_node->base, 16);
- temp_word = (u32)(p_mem_node->base >> 16);
- rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
+ rc = 0;
- RES_CHECK(p_mem_node->base + p_mem_node->length - 1, 16);
- temp_word = (u32)((p_mem_node->base + p_mem_node->length - 1) >> 16);
- rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
- } else {
- temp_word = 0xFFFF;
- rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
+ /* Here we actually find the devices and configure them */
+ for (device = 0; (device <= 0x1F) && !rc; device++) {
+ irqs.barber_pole = (irqs.barber_pole + 1) & 0x03;
- temp_word = 0x0000;
- rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+ ID = 0xFFFFFFFF;
+ pci_bus->number = hold_bus_node->base;
+ pci_bus_read_config_dword (pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID);
+ pci_bus->number = func->bus;
- kfree(hold_p_mem_node);
- hold_p_mem_node = NULL;
- }
+ if (ID != 0xFFFFFFFF) { /* device Present */
+ /* Setup slot structure. */
+ new_slot = pciehp_slot_create(hold_bus_node->base);
- /* Adjust this to compensate for extra adjustment in first loop */
- irqs.barber_pole--;
+ if (new_slot == NULL) {
+ /* Out of memory */
+ rc = -ENOMEM;
+ continue;
+ }
- rc = 0;
+ new_slot->bus = hold_bus_node->base;
+ new_slot->device = device;
+ new_slot->function = 0;
+ new_slot->is_a_board = 1;
+ new_slot->status = 0;
- /* Here we actually find the devices and configure them */
- for (device = 0; (device <= 0x1F) && !rc; device++) {
- irqs.barber_pole = (irqs.barber_pole + 1) & 0x03;
+ rc = configure_new_device(ctrl, new_slot, 1,
+ &temp_resources, func->bus,
+ func->device);
+ dbg("configure_new_device rc=0x%x\n",rc);
+ } /* End of IF (device in slot?) */
+ } /* End of FOR loop */
- ID = 0xFFFFFFFF;
- pci_bus->number = hold_bus_node->base;
- pci_bus_read_config_dword (pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID);
- pci_bus->number = func->bus;
+ if (rc) {
+ pciehp_destroy_resource_list(&temp_resources);
- if (ID != 0xFFFFFFFF) { /* device Present */
- /* Setup slot structure. */
- new_slot = pciehp_slot_create(hold_bus_node->base);
+ return_resource(&(resources->bus_head), hold_bus_node);
+ return_resource(&(resources->io_head), hold_IO_node);
+ return_resource(&(resources->mem_head), hold_mem_node);
+ return_resource(&(resources->p_mem_head), hold_p_mem_node);
+ return(rc);
+ }
- if (new_slot == NULL) {
- /* Out of memory */
- rc = -ENOMEM;
- continue;
+ /* save the interrupt routing information */
+ if (resources->irqs) {
+ resources->irqs->interrupt[0] = irqs.interrupt[0];
+ resources->irqs->interrupt[1] = irqs.interrupt[1];
+ resources->irqs->interrupt[2] = irqs.interrupt[2];
+ resources->irqs->interrupt[3] = irqs.interrupt[3];
+ resources->irqs->valid_INT = irqs.valid_INT;
+ } else if (!behind_bridge) {
+ /* We need to hook up the interrupts here */
+ for (cloop = 0; cloop < 4; cloop++) {
+ if (irqs.valid_INT & (0x01 << cloop)) {
+ rc = pciehp_set_irq(func->bus, func->device,
+ 0x0A + cloop, irqs.interrupt[cloop]);
+ if (rc) {
+ pciehp_destroy_resource_list (&temp_resources);
+ return_resource(&(resources->bus_head), hold_bus_node);
+ return_resource(&(resources->io_head), hold_IO_node);
+ return_resource(&(resources->mem_head), hold_mem_node);
+ return_resource(&(resources->p_mem_head), hold_p_mem_node);
+ return rc;
}
+ }
+ } /* end of for loop */
+ }
- new_slot->bus = hold_bus_node->base;
- new_slot->device = device;
- new_slot->function = 0;
- new_slot->is_a_board = 1;
- new_slot->status = 0;
+ /* Return unused bus resources
+ * First use the temporary node to store information for the board
+ */
+ if (hold_bus_node && bus_node && temp_resources.bus_head) {
+ hold_bus_node->length = bus_node->base - hold_bus_node->base;
- rc = configure_new_device(ctrl, new_slot, 1, &temp_resources, func->bus, func->device);
- dbg("configure_new_device rc=0x%x\n",rc);
- } /* End of IF (device in slot?) */
- } /* End of FOR loop */
+ hold_bus_node->next = func->bus_head;
+ func->bus_head = hold_bus_node;
- if (rc) {
- pciehp_destroy_resource_list(&temp_resources);
+ temp_byte = (u8)(temp_resources.bus_head->base - 1);
- return_resource(&(resources->bus_head), hold_bus_node);
- return_resource(&(resources->io_head), hold_IO_node);
- return_resource(&(resources->mem_head), hold_mem_node);
- return_resource(&(resources->p_mem_head), hold_p_mem_node);
- return(rc);
- }
+ /* set subordinate bus */
+ dbg("re-set subordinate bus = 0x%x\n", temp_byte);
+ rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte);
- /* save the interrupt routing information */
- if (resources->irqs) {
- resources->irqs->interrupt[0] = irqs.interrupt[0];
- resources->irqs->interrupt[1] = irqs.interrupt[1];
- resources->irqs->interrupt[2] = irqs.interrupt[2];
- resources->irqs->interrupt[3] = irqs.interrupt[3];
- resources->irqs->valid_INT = irqs.valid_INT;
- } else if (!behind_bridge) {
- /* We need to hook up the interrupts here */
- for (cloop = 0; cloop < 4; cloop++) {
- if (irqs.valid_INT & (0x01 << cloop)) {
- rc = pciehp_set_irq(func->bus, func->device,
- 0x0A + cloop, irqs.interrupt[cloop]);
- if (rc) {
- pciehp_destroy_resource_list (&temp_resources);
- return_resource(&(resources->bus_head), hold_bus_node);
- return_resource(&(resources->io_head), hold_IO_node);
- return_resource(&(resources->mem_head), hold_mem_node);
- return_resource(&(resources->p_mem_head), hold_p_mem_node);
- return rc;
- }
- }
- } /* end of for loop */
+ if (temp_resources.bus_head->length == 0) {
+ kfree(temp_resources.bus_head);
+ temp_resources.bus_head = NULL;
+ } else {
+ dbg("return bus res of b:d(0x%x:%x) base:len(0x%x:%x)\n",
+ func->bus, func->device, temp_resources.bus_head->base, temp_resources.bus_head->length);
+ return_resource(&(resources->bus_head), temp_resources.bus_head);
}
+ }
- /* Return unused bus resources
- * First use the temporary node to store information for the board
- */
- if (hold_bus_node && bus_node && temp_resources.bus_head) {
- hold_bus_node->length = bus_node->base - hold_bus_node->base;
-
- hold_bus_node->next = func->bus_head;
- func->bus_head = hold_bus_node;
+ /* If we have IO space available and there is some left,
+ * return the unused portion
+ */
+ if (hold_IO_node && temp_resources.io_head) {
+ io_node = do_pre_bridge_resource_split(&(temp_resources.io_head),
+ &hold_IO_node, 0x1000);
- temp_byte = (u8)(temp_resources.bus_head->base - 1);
+ /* Check if we were able to split something off */
+ if (io_node) {
+ hold_IO_node->base = io_node->base + io_node->length;
- /* set subordinate bus */
- dbg("re-set subordinate bus = 0x%x\n", temp_byte);
- rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte);
+ RES_CHECK(hold_IO_node->base, 8);
+ temp_byte = (u8)((hold_IO_node->base) >> 8);
+ rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte);
- if (temp_resources.bus_head->length == 0) {
- kfree(temp_resources.bus_head);
- temp_resources.bus_head = NULL;
- } else {
- dbg("return bus res of b:d(0x%x:%x) base:len(0x%x:%x)\n",
- func->bus, func->device, temp_resources.bus_head->base, temp_resources.bus_head->length);
- return_resource(&(resources->bus_head), temp_resources.bus_head);
- }
+ return_resource(&(resources->io_head), io_node);
}
- /* If we have IO space available and there is some left,
- * return the unused portion
- */
- if (hold_IO_node && temp_resources.io_head) {
- io_node = do_pre_bridge_resource_split(&(temp_resources.io_head),
- &hold_IO_node, 0x1000);
-
- /* Check if we were able to split something off */
- if (io_node) {
- hold_IO_node->base = io_node->base + io_node->length;
-
- RES_CHECK(hold_IO_node->base, 8);
- temp_byte = (u8)((hold_IO_node->base) >> 8);
- rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte);
-
- return_resource(&(resources->io_head), io_node);
- }
-
- io_node = do_bridge_resource_split(&(temp_resources.io_head), 0x1000);
+ io_node = do_bridge_resource_split(&(temp_resources.io_head), 0x1000);
- /* Check if we were able to split something off */
- if (io_node) {
- /* First use the temporary node to store information for the board */
- hold_IO_node->length = io_node->base - hold_IO_node->base;
+ /* Check if we were able to split something off */
+ if (io_node) {
+ /* First use the temporary node to store information for the board */
+ hold_IO_node->length = io_node->base - hold_IO_node->base;
- /* If we used any, add it to the board's list */
- if (hold_IO_node->length) {
- hold_IO_node->next = func->io_head;
- func->io_head = hold_IO_node;
+ /* If we used any, add it to the board's list */
+ if (hold_IO_node->length) {
+ hold_IO_node->next = func->io_head;
+ func->io_head = hold_IO_node;
- RES_CHECK(io_node->base - 1, 8);
- temp_byte = (u8)((io_node->base - 1) >> 8);
- rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
+ RES_CHECK(io_node->base - 1, 8);
+ temp_byte = (u8)((io_node->base - 1) >> 8);
+ rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
- return_resource(&(resources->io_head), io_node);
- } else {
- /* it doesn't need any IO */
- temp_byte = 0x00;
- rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
-
- return_resource(&(resources->io_head), io_node);
- kfree(hold_IO_node);
- }
+ return_resource(&(resources->io_head), io_node);
} else {
- /* it used most of the range */
- hold_IO_node->next = func->io_head;
- func->io_head = hold_IO_node;
+ /* it doesn't need any IO */
+ temp_byte = 0x00;
+ rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
+
+ return_resource(&(resources->io_head), io_node);
+ kfree(hold_IO_node);
}
- } else if (hold_IO_node) {
- /* it used the whole range */
+ } else {
+ /* it used most of the range */
hold_IO_node->next = func->io_head;
func->io_head = hold_IO_node;
}
+ } else if (hold_IO_node) {
+ /* it used the whole range */
+ hold_IO_node->next = func->io_head;
+ func->io_head = hold_IO_node;
+ }
- /* If we have memory space available and there is some left,
- * return the unused portion
- */
- if (hold_mem_node && temp_resources.mem_head) {
- mem_node = do_pre_bridge_resource_split(&(temp_resources.mem_head), &hold_mem_node, 0x100000L);
-
- /* Check if we were able to split something off */
- if (mem_node) {
- hold_mem_node->base = mem_node->base + mem_node->length;
+ /* If we have memory space available and there is some left,
+ * return the unused portion
+ */
+ if (hold_mem_node && temp_resources.mem_head) {
+ mem_node = do_pre_bridge_resource_split(&(temp_resources.mem_head), &hold_mem_node, 0x100000L);
- RES_CHECK(hold_mem_node->base, 16);
- temp_word = (u32)((hold_mem_node->base) >> 16);
- rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
+ /* Check if we were able to split something off */
+ if (mem_node) {
+ hold_mem_node->base = mem_node->base + mem_node->length;
- return_resource(&(resources->mem_head), mem_node);
- }
+ RES_CHECK(hold_mem_node->base, 16);
+ temp_word = (u16)((hold_mem_node->base) >> 16);
+ rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
- mem_node = do_bridge_resource_split(&(temp_resources.mem_head), 0x100000L);
+ return_resource(&(resources->mem_head), mem_node);
+ }
- /* Check if we were able to split something off */
- if (mem_node) {
- /* First use the temporary node to store information for the board */
- hold_mem_node->length = mem_node->base - hold_mem_node->base;
+ mem_node = do_bridge_resource_split(&(temp_resources.mem_head), 0x100000L);
- if (hold_mem_node->length) {
- hold_mem_node->next = func->mem_head;
- func->mem_head = hold_mem_node;
+ /* Check if we were able to split something off */
+ if (mem_node) {
+ /* First use the temporary node to store information for the board */
+ hold_mem_node->length = mem_node->base - hold_mem_node->base;
- /* configure end address */
- RES_CHECK(mem_node->base - 1, 16);
- temp_word = (u32)((mem_node->base - 1) >> 16);
- rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+ if (hold_mem_node->length) {
+ hold_mem_node->next = func->mem_head;
+ func->mem_head = hold_mem_node;
- /* Return unused resources to the pool */
- return_resource(&(resources->mem_head), mem_node);
- } else {
- /* it doesn't need any Mem */
- temp_word = 0x0000;
- rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+ /* configure end address */
+ RES_CHECK(mem_node->base - 1, 16);
+ temp_word = (u16)((mem_node->base - 1) >> 16);
+ rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
- return_resource(&(resources->mem_head), mem_node);
- kfree(hold_mem_node);
- }
+ /* Return unused resources to the pool */
+ return_resource(&(resources->mem_head), mem_node);
} else {
- /* it used most of the range */
- hold_mem_node->next = func->mem_head;
- func->mem_head = hold_mem_node;
+ /* it doesn't need any Mem */
+ temp_word = 0x0000;
+ rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+
+ return_resource(&(resources->mem_head), mem_node);
+ kfree(hold_mem_node);
}
- } else if (hold_mem_node) {
- /* it used the whole range */
+ } else {
+ /* it used most of the range */
hold_mem_node->next = func->mem_head;
func->mem_head = hold_mem_node;
}
+ } else if (hold_mem_node) {
+ /* it used the whole range */
+ hold_mem_node->next = func->mem_head;
+ func->mem_head = hold_mem_node;
+ }
- /* If we have prefetchable memory space available and there is some
- * left at the end, return the unused portion
- */
- if (hold_p_mem_node && temp_resources.p_mem_head) {
- p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head),
- &hold_p_mem_node, 0x100000L);
-
- /* Check if we were able to split something off */
- if (p_mem_node) {
- hold_p_mem_node->base = p_mem_node->base + p_mem_node->length;
+ /* If we have prefetchable memory space available and there is some
+ * left at the end, return the unused portion
+ */
+ if (hold_p_mem_node && temp_resources.p_mem_head) {
+ p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head),
+ &hold_p_mem_node, 0x100000L);
- RES_CHECK(hold_p_mem_node->base, 16);
- temp_word = (u32)((hold_p_mem_node->base) >> 16);
- rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
+ /* Check if we were able to split something off */
+ if (p_mem_node) {
+ hold_p_mem_node->base = p_mem_node->base + p_mem_node->length;
- return_resource(&(resources->p_mem_head), p_mem_node);
- }
+ RES_CHECK(hold_p_mem_node->base, 16);
+ temp_word = (u16)((hold_p_mem_node->base) >> 16);
+ rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
- p_mem_node = do_bridge_resource_split(&(temp_resources.p_mem_head), 0x100000L);
+ return_resource(&(resources->p_mem_head), p_mem_node);
+ }
- /* Check if we were able to split something off */
- if (p_mem_node) {
- /* First use the temporary node to store information for the board */
- hold_p_mem_node->length = p_mem_node->base - hold_p_mem_node->base;
+ p_mem_node = do_bridge_resource_split(&(temp_resources.p_mem_head), 0x100000L);
- /* If we used any, add it to the board's list */
- if (hold_p_mem_node->length) {
- hold_p_mem_node->next = func->p_mem_head;
- func->p_mem_head = hold_p_mem_node;
+ /* Check if we were able to split something off */
+ if (p_mem_node) {
+ /* First use the temporary node to store information for the board */
+ hold_p_mem_node->length = p_mem_node->base - hold_p_mem_node->base;
- RES_CHECK(p_mem_node->base - 1, 16);
- temp_word = (u32)((p_mem_node->base - 1) >> 16);
- rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+ /* If we used any, add it to the board's list */
+ if (hold_p_mem_node->length) {
+ hold_p_mem_node->next = func->p_mem_head;
+ func->p_mem_head = hold_p_mem_node;
- return_resource(&(resources->p_mem_head), p_mem_node);
- } else {
- /* it doesn't need any PMem */
- temp_word = 0x0000;
- rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+ RES_CHECK(p_mem_node->base - 1, 16);
+ temp_word = (u16)((p_mem_node->base - 1) >> 16);
+ rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
- return_resource(&(resources->p_mem_head), p_mem_node);
- kfree(hold_p_mem_node);
- }
+ return_resource(&(resources->p_mem_head), p_mem_node);
} else {
- /* it used the most of the range */
- hold_p_mem_node->next = func->p_mem_head;
- func->p_mem_head = hold_p_mem_node;
+ /* it doesn't need any PMem */
+ temp_word = 0x0000;
+ rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+
+ return_resource(&(resources->p_mem_head), p_mem_node);
+ kfree(hold_p_mem_node);
}
- } else if (hold_p_mem_node) {
- /* it used the whole range */
+ } else {
+ /* it used the most of the range */
hold_p_mem_node->next = func->p_mem_head;
func->p_mem_head = hold_p_mem_node;
}
+ } else if (hold_p_mem_node) {
+ /* it used the whole range */
+ hold_p_mem_node->next = func->p_mem_head;
+ func->p_mem_head = hold_p_mem_node;
+ }
- /* We should be configuring an IRQ and the bridge's base address
- * registers if it needs them. Although we have never seen such
- * a device
- */
+ /* We should be configuring an IRQ and the bridge's base address
+ * registers if it needs them. Although we have never seen such
+ * a device
+ */
+
+ pciehprm_enable_card(ctrl, func, PCI_HEADER_TYPE_BRIDGE);
+
+ dbg("PCI Bridge Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, func->device, func->function);
+
+ return rc;
+}
+
+/**
+ * configure_new_function - Configures the PCI header information of one device
+ *
+ * @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
+ *
+ * Calls itself recursively for bridged devices.
+ * Returns 0 if success
+ *
+ */
+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)
+{
+ int cloop;
+ u8 temp_byte;
+ u8 class_code;
+ u16 temp_word;
+ u32 rc;
+ u32 temp_register;
+ u32 base;
+ unsigned int devfn;
+ struct pci_resource *mem_node;
+ struct pci_resource *io_node;
+ struct pci_bus lpci_bus, *pci_bus;
+
+ memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
+ pci_bus = &lpci_bus;
+ pci_bus->number = func->bus;
+ devfn = PCI_DEVFN(func->device, func->function);
+
+ /* Check for Bridge */
+ rc = pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &temp_byte);
+ if (rc)
+ return rc;
+ dbg("%s: bus %x dev %x func %x temp_byte = %x\n", __FUNCTION__,
+ func->bus, func->device, func->function, temp_byte);
- pciehprm_enable_card(ctrl, func, PCI_HEADER_TYPE_BRIDGE);
+ if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */
+ rc = configure_new_bridge(ctrl, func, behind_bridge, resources,
+ pci_bus);
- dbg("PCI Bridge Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, func->device, func->function);
+ if (rc)
+ return rc;
} else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
/* Standard device */
u64 base64;
- rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
+ rc = pci_bus_read_config_byte(pci_bus, devfn, 0x0B, &class_code);
if (class_code == PCI_BASE_CLASS_DISPLAY)
- return (DEVICE_TYPE_NOT_SUPPORTED);
+ return DEVICE_TYPE_NOT_SUPPORTED;
/* Figure out IO and memory needs */
for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) {
else {
if (prefetchable)
dbg("using MEM for PMEM\n");
- mem_node=get_resource(&(resources->mem_head), (ulong)base);
+ mem_node = get_resource(&(resources->mem_head), (ulong)base);
}
/* allocate the resource to the board */
} /* End of Not-A-Bridge else */
else {
/* It's some strange type of PCI adapter (Cardbus?) */
- return(DEVICE_TYPE_NOT_SUPPORTED);
+ return DEVICE_TYPE_NOT_SUPPORTED;
}
func->configured = 1;
return 0;
}
-