Commit c61b1d93 authored by Rolf Eike Beer's avatar Rolf Eike Beer Committed by Deepak Saxena

[PATCH] PCI Express Hotplug: splut pciehp_ctrl.c::configure_new_function

configure_new_function is way too big (>600 lines). Split it in 2 functions,
one for the new functions and one for bridges. And split out a small piece
from the bridge function which is used twice to it's own function.

Patch is huge because of the identation changes but does nothing than the
split and some minor coding style changes.
parent 30c6a0e8
...@@ -1958,36 +1958,58 @@ static u32 configure_new_device(struct controller * ctrl, struct pci_func * func ...@@ -1958,36 +1958,58 @@ static u32 configure_new_device(struct controller * ctrl, struct pci_func * func
return 0; return 0;
} }
/* /*
* Configuration logic that involves the hotplug data structures and * Configuration logic that involves the hotplug data structures and
* their bookkeeping * their bookkeeping
*/ */
/** /**
* configure_new_function - Configures the PCI header information of one device * configure_bridge: fill bridge's registers, either configure or disable it.
*
* @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, static int
u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev) 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; int cloop;
u8 temp_byte; u8 temp_byte;
u8 device; u8 device;
u8 class_code;
u16 temp_word; u16 temp_word;
u32 rc; u32 rc;
u32 temp_register;
u32 base;
u32 ID; u32 ID;
unsigned int devfn; unsigned int devfn;
struct pci_resource *mem_node; struct pci_resource *mem_node;
...@@ -2000,483 +2022,480 @@ static int configure_new_function(struct controller * ctrl, struct pci_func * fu ...@@ -2000,483 +2022,480 @@ static int configure_new_function(struct controller * ctrl, struct pci_func * fu
struct pci_resource *hold_bus_node; struct pci_resource *hold_bus_node;
struct irq_mapping irqs; struct irq_mapping irqs;
struct pci_func *new_slot; struct pci_func *new_slot;
struct pci_bus lpci_bus, *pci_bus;
struct resource_lists temp_resources; 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); devfn = PCI_DEVFN(func->device, func->function);
/* Check for Bridge */ /* set Primary bus */
rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &temp_byte); 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) if (rc)
return 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 */ /* find range of busses to use */
if (!bus_node) { bus_node = get_max_resource(&resources->bus_head, 1L);
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 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 */ /* If we don't have any busses to allocate, we can't continue */
temp_byte = (u8)(bus_node->base + bus_node->length - 1); if (!bus_node) {
dbg("set subordinate bus = 0x%x\n", temp_byte); err("Got NO bus resource to use\n");
rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte); return -ENOMEM;
if (rc) }
return rc; 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) */ /* set Secondary bus */
rc = pciehprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_BRIDGE); temp_byte = (u8)bus_node->base;
if (rc) dbg("set Secondary bus = 0x%x\n", temp_byte);
return rc; 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); /* Set HP parameters (Cache Line Size, Latency Timer) */
if (io_node) { rc = pciehprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_BRIDGE);
dbg("io_node(base, len, next) (%x, %x, %p)\n", io_node->base, io_node->length, io_node->next); if (rc)
} return rc;
mem_node = get_max_resource(&(resources->mem_head), 0x100000L); /* Setup the IO, memory, and prefetchable windows */
if (mem_node) {
dbg("mem_node(base, len, next) (%x, %x, %p)\n", mem_node->base, mem_node->length, mem_node->next);
}
if (resources->p_mem_head) io_node = get_max_resource(&(resources->io_head), 0x1000L);
p_mem_node = get_max_resource(&(resources->p_mem_head), 0x100000L); if (io_node) {
else { dbg("io_node(base, len, next) (%x, %x, %p)\n", io_node->base,
/* io_node->length, io_node->next);
* 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);
}
/* set up the IRQ info */ mem_node = get_max_resource(&(resources->mem_head), 0x100000L);
if (!resources->irqs) { if (mem_node) {
irqs.barber_pole = 0; dbg("mem_node(base, len, next) (%x, %x, %p)\n", mem_node->base,
irqs.interrupt[0] = 0; mem_node->length, mem_node->next);
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;
}
/* set up resource lists that are now aligned on top and bottom if (resources->p_mem_head)
* for anything behind the bridge. p_mem_node = get_max_resource(&(resources->p_mem_head), 0x100000L);
*/ else {
temp_resources.bus_head = bus_node; /*
temp_resources.io_head = io_node; * In some platform implementation, MEM and PMEM are not
temp_resources.mem_head = mem_node; * distinguished, and hence ACPI _CRS has only MEM entries
temp_resources.p_mem_head = p_mem_node; * for both MEM and PMEM.
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 = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); dbg("using MEM for PMEM\n");
hold_IO_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); p_mem_node = get_max_resource(&(resources->mem_head), 0x100000L);
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 (p_mem_node) {
dbg("p_mem_node(base, len, next) (%x, %x, %p)\n", p_mem_node->base,
if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) { p_mem_node->length, p_mem_node->next);
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)); /* 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;
}
bus_node->base += 1; /* set up resource lists that are now aligned on top and bottom
bus_node->length -= 1; * for anything behind the bridge.
bus_node->next = NULL; */
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);
/* If we have IO resources copy them and fill in the bridge's if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) {
* IO range registers kfree(hold_bus_node);
*/ kfree(hold_IO_node);
if (io_node) { kfree(hold_mem_node);
memcpy(hold_IO_node, io_node, sizeof(struct pci_resource)); kfree(hold_p_mem_node);
io_node->next = NULL;
/* set IO base and Limit registers */ return 1;
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); memcpy(hold_bus_node, bus_node, sizeof(struct pci_resource));
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;
}
/* If we have memory resources copy them and fill in the bridge's bus_node->base += 1;
* memory range registers. Otherwise, fill in the range bus_node->length -= 1;
* registers with values that disable them. bus_node->next = NULL;
*/
if (mem_node) {
memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource));
mem_node->next = NULL;
/* set Mem base and Limit registers */ /* If we have IO resources copy them and fill in the bridge's
RES_CHECK(mem_node->base, 16); * IO range registers
temp_word = (u32)(mem_node->base >> 16); */
rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); if (io_node) {
memcpy(hold_IO_node, io_node, sizeof(struct pci_resource));
RES_CHECK(mem_node->base + mem_node->length - 1, 16); io_node->next = NULL;
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); /* set IO base and Limit registers */
} else { RES_CHECK(io_node->base, 8);
temp_word = 0xFFFF; temp_byte = (u8)(io_node->base >> 8);
rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); 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; /* If we have memory resources copy them and fill in the bridge's
rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); * 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); /* If we have prefetchable memory resources copy them and
hold_mem_node = NULL; * 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 /* Adjust this to compensate for extra adjustment in first loop */
* fill in the bridge's memory range registers. Otherwise, irqs.barber_pole--;
* 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;
/* set Pre Mem base and Limit registers */ rc = 0;
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);
RES_CHECK(p_mem_node->base + p_mem_node->length - 1, 16); /* Here we actually find the devices and configure them */
temp_word = (u32)((p_mem_node->base + p_mem_node->length - 1) >> 16); for (device = 0; (device <= 0x1F) && !rc; device++) {
rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); irqs.barber_pole = (irqs.barber_pole + 1) & 0x03;
} else {
temp_word = 0xFFFF;
rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
temp_word = 0x0000; ID = 0xFFFFFFFF;
rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); 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); if (ID != 0xFFFFFFFF) { /* device Present */
hold_p_mem_node = NULL; /* Setup slot structure. */
} new_slot = pciehp_slot_create(hold_bus_node->base);
/* Adjust this to compensate for extra adjustment in first loop */ if (new_slot == NULL) {
irqs.barber_pole--; /* 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 */ rc = configure_new_device(ctrl, new_slot, 1,
for (device = 0; (device <= 0x1F) && !rc; device++) { &temp_resources, func->bus,
irqs.barber_pole = (irqs.barber_pole + 1) & 0x03; func->device);
dbg("configure_new_device rc=0x%x\n",rc);
} /* End of IF (device in slot?) */
} /* End of FOR loop */
ID = 0xFFFFFFFF; if (rc) {
pci_bus->number = hold_bus_node->base; pciehp_destroy_resource_list(&temp_resources);
pci_bus_read_config_dword (pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID);
pci_bus->number = func->bus;
if (ID != 0xFFFFFFFF) { /* device Present */ return_resource(&(resources->bus_head), hold_bus_node);
/* Setup slot structure. */ return_resource(&(resources->io_head), hold_IO_node);
new_slot = pciehp_slot_create(hold_bus_node->base); return_resource(&(resources->mem_head), hold_mem_node);
return_resource(&(resources->p_mem_head), hold_p_mem_node);
return(rc);
}
if (new_slot == NULL) { /* save the interrupt routing information */
/* Out of memory */ if (resources->irqs) {
rc = -ENOMEM; resources->irqs->interrupt[0] = irqs.interrupt[0];
continue; 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; /* Return unused bus resources
new_slot->device = device; * First use the temporary node to store information for the board
new_slot->function = 0; */
new_slot->is_a_board = 1; if (hold_bus_node && bus_node && temp_resources.bus_head) {
new_slot->status = 0; 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); hold_bus_node->next = func->bus_head;
dbg("configure_new_device rc=0x%x\n",rc); func->bus_head = hold_bus_node;
} /* End of IF (device in slot?) */
} /* End of FOR loop */
if (rc) { temp_byte = (u8)(temp_resources.bus_head->base - 1);
pciehp_destroy_resource_list(&temp_resources);
return_resource(&(resources->bus_head), hold_bus_node); /* set subordinate bus */
return_resource(&(resources->io_head), hold_IO_node); dbg("re-set subordinate bus = 0x%x\n", temp_byte);
return_resource(&(resources->mem_head), hold_mem_node); rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte);
return_resource(&(resources->p_mem_head), hold_p_mem_node);
return rc;
}
/* save the interrupt routing information */ if (temp_resources.bus_head->length == 0) {
if (resources->irqs) { kfree(temp_resources.bus_head);
resources->irqs->interrupt[0] = irqs.interrupt[0]; temp_resources.bus_head = NULL;
resources->irqs->interrupt[1] = irqs.interrupt[1]; } else {
resources->irqs->interrupt[2] = irqs.interrupt[2]; dbg("return bus res of b:d(0x%x:%x) base:len(0x%x:%x)\n",
resources->irqs->interrupt[3] = irqs.interrupt[3]; func->bus, func->device, temp_resources.bus_head->base, temp_resources.bus_head->length);
resources->irqs->valid_INT = irqs.valid_INT; return_resource(&(resources->bus_head), temp_resources.bus_head);
} 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 */
} }
}
/* Return unused bus resources /* If we have IO space available and there is some left,
* First use the temporary node to store information for the board * return the unused portion
*/ */
if (hold_bus_node && bus_node && temp_resources.bus_head) { if (hold_IO_node && temp_resources.io_head) {
hold_bus_node->length = bus_node->base - hold_bus_node->base; io_node = do_pre_bridge_resource_split(&(temp_resources.io_head),
&hold_IO_node, 0x1000);
hold_bus_node->next = func->bus_head;
func->bus_head = hold_bus_node;
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 */ RES_CHECK(hold_IO_node->base, 8);
dbg("re-set subordinate bus = 0x%x\n", temp_byte); temp_byte = (u8)((hold_IO_node->base) >> 8);
rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte); rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte);
if (temp_resources.bus_head->length == 0) { return_resource(&(resources->io_head), io_node);
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);
}
} }
/* If we have IO space available and there is some left, io_node = do_bridge_resource_split(&(temp_resources.io_head), 0x1000);
* 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);
/* Check if we were able to split something off */ /* Check if we were able to split something off */
if (io_node) { if (io_node) {
/* First use the temporary node to store information for the board */ /* First use the temporary node to store information for the board */
hold_IO_node->length = io_node->base - hold_IO_node->base; 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;
RES_CHECK(io_node->base - 1, 8); /* If we used any, add it to the board's list */
temp_byte = (u8)((io_node->base - 1) >> 8); if (hold_IO_node->length) {
rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte); hold_IO_node->next = func->io_head;
func->io_head = hold_IO_node;
return_resource(&(resources->io_head), io_node); RES_CHECK(io_node->base - 1, 8);
} else { temp_byte = (u8)((io_node->base - 1) >> 8);
/* it doesn't need any IO */ rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
temp_byte = 0x00;
rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
return_resource(&(resources->io_head), io_node); return_resource(&(resources->io_head), io_node);
kfree(hold_IO_node);
}
} else { } else {
/* it used most of the range */ /* it doesn't need any IO */
hold_IO_node->next = func->io_head; temp_byte = 0x00;
func->io_head = hold_IO_node; 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) { } else {
/* it used the whole range */ /* it used most of the range */
hold_IO_node->next = func->io_head; hold_IO_node->next = func->io_head;
func->io_head = hold_IO_node; 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, /* If we have memory space available and there is some left,
* return the unused portion * return the unused portion
*/ */
if (hold_mem_node && temp_resources.mem_head) { if (hold_mem_node && temp_resources.mem_head) {
mem_node = do_pre_bridge_resource_split(&(temp_resources.mem_head), &hold_mem_node, 0x100000L); 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;
RES_CHECK(hold_mem_node->base, 16); /* Check if we were able to split something off */
temp_word = (u32)((hold_mem_node->base) >> 16); if (mem_node) {
rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); 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 */ mem_node = do_bridge_resource_split(&(temp_resources.mem_head), 0x100000L);
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;
if (hold_mem_node->length) { /* Check if we were able to split something off */
hold_mem_node->next = func->mem_head; if (mem_node) {
func->mem_head = hold_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 */ if (hold_mem_node->length) {
RES_CHECK(mem_node->base - 1, 16); hold_mem_node->next = func->mem_head;
temp_word = (u32)((mem_node->base - 1) >> 16); func->mem_head = hold_mem_node;
rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
/* Return unused resources to the pool */ /* configure end address */
return_resource(&(resources->mem_head), mem_node); RES_CHECK(mem_node->base - 1, 16);
} else { temp_word = (u16)((mem_node->base - 1) >> 16);
/* it doesn't need any Mem */ rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
temp_word = 0x0000;
rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
return_resource(&(resources->mem_head), mem_node); /* Return unused resources to the pool */
kfree(hold_mem_node); return_resource(&(resources->mem_head), mem_node);
}
} else { } else {
/* it used most of the range */ /* it doesn't need any Mem */
hold_mem_node->next = func->mem_head; temp_word = 0x0000;
func->mem_head = hold_mem_node; 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) { } else {
/* it used the whole range */ /* it used most of the range */
hold_mem_node->next = func->mem_head; hold_mem_node->next = func->mem_head;
func->mem_head = hold_mem_node; 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 /* If we have prefetchable memory space available and there is some
* left at the end, return the unused portion * left at the end, return the unused portion
*/ */
if (hold_p_mem_node && temp_resources.p_mem_head) { if (hold_p_mem_node && temp_resources.p_mem_head) {
p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head), p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head),
&hold_p_mem_node, 0x100000L); &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;
RES_CHECK(hold_p_mem_node->base, 16); /* Check if we were able to split something off */
temp_word = (u32)((hold_p_mem_node->base) >> 16); if (p_mem_node) {
rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); 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 */ p_mem_node = do_bridge_resource_split(&(temp_resources.p_mem_head), 0x100000L);
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;
/* If we used any, add it to the board's list */ /* Check if we were able to split something off */
if (hold_p_mem_node->length) { if (p_mem_node) {
hold_p_mem_node->next = func->p_mem_head; /* First use the temporary node to store information for the board */
func->p_mem_head = hold_p_mem_node; hold_p_mem_node->length = p_mem_node->base - hold_p_mem_node->base;
RES_CHECK(p_mem_node->base - 1, 16); /* If we used any, add it to the board's list */
temp_word = (u32)((p_mem_node->base - 1) >> 16); if (hold_p_mem_node->length) {
rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); 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); RES_CHECK(p_mem_node->base - 1, 16);
} else { temp_word = (u16)((p_mem_node->base - 1) >> 16);
/* it doesn't need any PMem */ rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
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); return_resource(&(resources->p_mem_head), p_mem_node);
kfree(hold_p_mem_node);
}
} else { } else {
/* it used the most of the range */ /* it doesn't need any PMem */
hold_p_mem_node->next = func->p_mem_head; temp_word = 0x0000;
func->p_mem_head = hold_p_mem_node; 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) { } else {
/* it used the whole range */ /* it used the most of the range */
hold_p_mem_node->next = func->p_mem_head; hold_p_mem_node->next = func->p_mem_head;
func->p_mem_head = hold_p_mem_node; 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 /* We should be configuring an IRQ and the bridge's base address
* registers if it needs them. Although we have never seen such * registers if it needs them. Although we have never seen such
* a device * a device
*/ */
pciehprm_enable_card(ctrl, func, PCI_HEADER_TYPE_BRIDGE); 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); 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);
if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */
rc = configure_new_bridge(ctrl, func, behind_bridge, resources,
pci_bus);
if (rc)
return rc;
} else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) { } else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
/* Standard device */ /* Standard device */
u64 base64; 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) if (class_code == PCI_BASE_CLASS_DISPLAY)
return DEVICE_TYPE_NOT_SUPPORTED; return DEVICE_TYPE_NOT_SUPPORTED;
...@@ -2538,7 +2557,7 @@ static int configure_new_function(struct controller * ctrl, struct pci_func * fu ...@@ -2538,7 +2557,7 @@ static int configure_new_function(struct controller * ctrl, struct pci_func * fu
else { else {
if (prefetchable) if (prefetchable)
dbg("using MEM for PMEM\n"); 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 */ /* allocate the resource to the board */
...@@ -2624,4 +2643,3 @@ static int configure_new_function(struct controller * ctrl, struct pci_func * fu ...@@ -2624,4 +2643,3 @@ static int configure_new_function(struct controller * ctrl, struct pci_func * fu
return 0; return 0;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment