// SPDX-License-Identifier: GPL-2.0+/* * IBM Hot Plug Controller Driver * * Written By: Irene Zubarev, IBM Corporation * * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2001,2002 IBM Corp. * * All rights reserved. * * Send feedback to <gregkh@us.ibm.com> * */ #include <linux/module.h>#include <linux/slab.h>#include <linux/pci.h>#include <linux/list.h>#include "ibmphp.h" static int configure_device(struct pci_func *);static int configure_bridge(struct pci_func **, u8);static struct res_needed *scan_behind_bridge(struct pci_func *, u8);static int add_new_bus(struct bus_node *, struct resource_node *, struct resource_node *, struct resource_node *, u8);static u8 find_sec_number(u8 primary_busno, u8 slotno); /* * NOTE..... If BIOS doesn't provide default routing, we assign: * 9 for SCSI, 10 for LAN adapters, and 11 for everything else. * If adapter is bridged, then we assign 11 to it and devices behind it. * We also assign the same irq numbers for multi function devices. * These are PIC mode, so shouldn't matter n.e.ways (hopefully) */static void assign_alt_irq(struct pci_func *cur_func, u8 class_code){ int j; for (j = 0; j < 4; j++) { if (cur_func->irq[j] == 0xff) { switch (class_code) { case PCI_BASE_CLASS_STORAGE: cur_func->irq[j] = SCSI_IRQ; break; case PCI_BASE_CLASS_NETWORK: cur_func->irq[j] = LAN_IRQ; break; default: cur_func->irq[j] = OTHER_IRQ; break; } } }} /* * Configures the device to be added (will allocate needed resources if it * can), the device can be a bridge or a regular pci device, can also be * multi-functional * * Input: function to be added * * TO DO: The error case with Multifunction device or multi function bridge, * if there is an error, will need to go through all previous functions and * unconfigure....or can add some code into unconfigure_card.... */int ibmphp_configure_card(struct pci_func *func, u8 slotno){ u16 vendor_id; u32 class; u8 class_code; u8 hdr_type, device, sec_number; u8 function; struct pci_func *newfunc; /* for multi devices */ struct pci_func *cur_func, *prev_func; int rc, i, j; int cleanup_count; u8 flag; u8 valid_device = 0x00; /* to see if we are able to read from card any device info at all */ debug("inside configure_card, func->busno = %x\n", func->busno); device = func->device; cur_func = func; /* We only get bus and device from IRQ routing table. So at this point, * func->busno is correct, and func->device contains only device (at the 5 * highest bits) */ /* For every function on the card */ for (function = 0x00; function < 0x08; function++) { unsigned int devfn = PCI_DEVFN(device, function); ibmphp_pci_bus->number = cur_func->busno; cur_func->function = function; debug("inside the loop, cur_func->busno = %x, cur_func->device = %x, cur_func->function = %x\n", cur_func->busno, cur_func->device, cur_func->function); pci_bus_read_config_word(ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id); debug("vendor_id is %x\n", vendor_id); if (vendor_id != PCI_VENDOR_ID_NOTVALID) { /* found correct device!!! */ debug("found valid device, vendor_id = %x\n", vendor_id); ++valid_device; /* header: x x x x x x x x * | |___________|=> 1=PPB bridge, 0=normal device, 2=CardBus Bridge * |_=> 0 = single function device, 1 = multi-function device */ pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type); pci_bus_read_config_dword(ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class); class_code = class >> 24; debug("hrd_type = %x, class = %x, class_code %x\n", hdr_type, class, class_code); class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ if (class == PCI_CLASS_NOT_DEFINED_VGA) { err("The device %x is VGA compatible and as is not supported for hot plugging. " "Please choose another device.\n", cur_func->device); return -ENODEV; } else if (class == PCI_CLASS_DISPLAY_VGA) { err("The device %x is not supported for hot plugging. Please choose another device.\n", cur_func->device); return -ENODEV; } switch (hdr_type) { case PCI_HEADER_TYPE_NORMAL: debug("single device case.... vendor id = %x, hdr_type = %x, class = %x\n", vendor_id, hdr_type, class); assign_alt_irq(cur_func, class_code); rc = configure_device(cur_func); if (rc < 0) { /* We need to do this in case some other BARs were properly inserted */ err("was not able to configure devfunc %x on bus %x.\n", cur_func->device, cur_func->busno); cleanup_count = 6; goto error; } cur_func->next = NULL; function = 0x8; break; case PCI_HEADER_TYPE_MULTIDEVICE: assign_alt_irq(cur_func, class_code); rc = configure_device(cur_func); if (rc < 0) { /* We need to do this in case some other BARs were properly inserted */ err("was not able to configure devfunc %x on bus %x...bailing out\n", cur_func->device, cur_func->busno); cleanup_count = 6; goto error; } newfunc = kzalloc_obj(*newfunc); if (!newfunc) return -ENOMEM; newfunc->busno = cur_func->busno; newfunc->device = device; cur_func->next = newfunc; cur_func = newfunc; for (j = 0; j < 4; j++) newfunc->irq[j] = cur_func->irq[j]; break; case PCI_HEADER_TYPE_MULTIBRIDGE: class >>= 8; if (class != PCI_CLASS_BRIDGE_PCI) { err("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. Please insert another card.\n", cur_func->device); return -ENODEV; } assign_alt_irq(cur_func, class_code); rc = configure_bridge(&cur_func, slotno); if (rc == -ENODEV) { err("You chose to insert Single Bridge, or nested bridges, this is not supported...\n"); err("Bus %x, devfunc %x\n", cur_func->busno, cur_func->device); return rc; } if (rc) { /* We need to do this in case some other BARs were properly inserted */ err("was not able to hot-add PPB properly.\n"); func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ cleanup_count = 2; goto error; } pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); flag = 0; for (i = 0; i < 32; i++) { if (func->devices[i]) { newfunc = kzalloc_obj(*newfunc); if (!newfunc) return -ENOMEM; newfunc->busno = sec_number; newfunc->device = (u8) i; for (j = 0; j < 4; j++) newfunc->irq[j] = cur_func->irq[j]; if (flag) { for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ; prev_func->next = newfunc; } else cur_func->next = newfunc; rc = ibmphp_configure_card(newfunc, slotno); /* This could only happen if kmalloc failed */ if (rc) { /* We need to do this in case bridge itself got configured properly, but devices behind it failed */ func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ cleanup_count = 2; goto error; } flag = 1; } } newfunc = kzalloc_obj(*newfunc); if (!newfunc) return -ENOMEM; newfunc->busno = cur_func->busno; newfunc->device = device; for (j = 0; j < 4; j++) newfunc->irq[j] = cur_func->irq[j]; for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next); prev_func->next = newfunc; cur_func = newfunc; break; case PCI_HEADER_TYPE_BRIDGE: class >>= 8; debug("class now is %x\n", class); if (class != PCI_CLASS_BRIDGE_PCI) { err("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. Please insert another card.\n", cur_func->device); return -ENODEV; } assign_alt_irq(cur_func, class_code); debug("cur_func->busno b4 configure_bridge is %x\n", cur_func->busno); rc = configure_bridge(&cur_func, slotno); if (rc == -ENODEV) { err("You chose to insert Single Bridge, or nested bridges, this is not supported...\n"); err("Bus %x, devfunc %x\n", cur_func->busno, cur_func->device); return rc; } if (rc) { /* We need to do this in case some other BARs were properly inserted */ func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ err("was not able to hot-add PPB properly.\n"); cleanup_count = 2; goto error; } debug("cur_func->busno = %x, device = %x, function = %x\n", cur_func->busno, device, function); pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); debug("after configuring bridge..., sec_number = %x\n", sec_number); flag = 0; for (i = 0; i < 32; i++) { if (func->devices[i]) { debug("inside for loop, device is %x\n", i); newfunc = kzalloc_obj(*newfunc); if (!newfunc) return -ENOMEM; newfunc->busno = sec_number; newfunc->device = (u8) i; for (j = 0; j < 4; j++) newfunc->irq[j] = cur_func->irq[j]; if (flag) { for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next); prev_func->next = newfunc; } else cur_func->next = newfunc; rc = ibmphp_configure_card(newfunc, slotno); /* Again, this case should not happen... For complete paranoia, will need to call remove_bus */ if (rc) { /* We need to do this in case some other BARs were properly inserted */ func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ cleanup_count = 2; goto error; } flag = 1; } } function = 0x8; break; default: err("MAJOR PROBLEM!!!!, header type not supported? %x\n", hdr_type); return -ENXIO; } /* end of switch */ } /* end of valid device */ } /* end of for */ if (!valid_device) { err("Cannot find any valid devices on the card. Or unable to read from card.\n"); return -ENODEV; } return 0; error: for (i = 0; i < cleanup_count; i++) { if (cur_func->io[i]) { ibmphp_remove_resource(cur_func->io[i]); cur_func->io[i] = NULL; } else if (cur_func->pfmem[i]) { ibmphp_remove_resource(cur_func->pfmem[i]); cur_func->pfmem[i] = NULL; } else if (cur_func->mem[i]) { ibmphp_remove_resource(cur_func->mem[i]); cur_func->mem[i] = NULL; } } return rc;} /* * This function configures the pci BARs of a single device. * Input: pointer to the pci_func * Output: configured PCI, 0, or error */static int configure_device(struct pci_func *func){ u32 bar[6]; static const u32 address[] = { PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2, PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5, 0 }; u8 irq; int count; int len[6]; struct resource_node *io[6]; struct resource_node *mem[6]; struct resource_node *mem_tmp; struct resource_node *pfmem[6]; unsigned int devfn; debug("%s - inside\n", __func__); devfn = PCI_DEVFN(func->device, func->function); ibmphp_pci_bus->number = func->busno; for (count = 0; address[count]; count++) { /* for 6 BARs */ /* not sure if i need this. per scott, said maybe need * something like this if devices don't adhere 100% to the spec, so don't want to write to the reserved bits pcibios_read_config_byte(cur_func->busno, cur_func->device, PCI_BASE_ADDRESS_0 + 4 * count, &tmp); if (tmp & 0x01) // IO pcibios_write_config_dword(cur_func->busno, cur_func->device, PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFD); else // Memory pcibios_write_config_dword(cur_func->busno, cur_func->device, PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFF); */ pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF); pci_bus_read_config_dword(ibmphp_pci_bus, devfn, address[count], &bar[count]); if (!bar[count]) /* This BAR is not implemented */ continue; debug("Device %x BAR %d wants %x\n", func->device, count, bar[count]); if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) { /* This is IO */ debug("inside IO SPACE\n"); len[count] = bar[count] & 0xFFFFFFFC; len[count] = ~len[count] + 1; debug("len[count] in IO %x, count %d\n", len[count], count); io[count] = kzalloc_obj(struct resource_node); if (!io[count]) return -ENOMEM; io[count]->type = IO; io[count]->busno = func->busno; io[count]->devfunc = PCI_DEVFN(func->device, func->function); io[count]->len = len[count]; if (ibmphp_check_resource(io[count], 0) == 0) { ibmphp_add_resource(io[count]); func->io[count] = io[count]; } else { err("cannot allocate requested io for bus %x device %x function %x len %x\n", func->busno, func->device, func->function, len[count]); kfree(io[count]); return -EIO; } pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], func->io[count]->start); /* _______________This is for debugging purposes only_____________________ */ debug("b4 writing, the IO address is %x\n", func->io[count]->start); pci_bus_read_config_dword(ibmphp_pci_bus, devfn, address[count], &bar[count]); debug("after writing.... the start address is %x\n", bar[count]); /* _________________________________________________________________________*/ } else { /* This is Memory */ if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) { /* pfmem */ debug("PFMEM SPACE\n"); len[count] = bar[count] & 0xFFFFFFF0; len[count] = ~len[count] + 1; debug("len[count] in PFMEM %x, count %d\n", len[count], count); pfmem[count] = kzalloc_obj(struct resource_node); if (!pfmem[count]) return -ENOMEM; pfmem[count]->type = PFMEM; pfmem[count]->busno = func->busno; pfmem[count]->devfunc = PCI_DEVFN(func->device, func->function); pfmem[count]->len = len[count]; pfmem[count]->fromMem = 0; if (ibmphp_check_resource(pfmem[count], 0) == 0) { ibmphp_add_resource(pfmem[count]); func->pfmem[count] = pfmem[count]; } else { mem_tmp = kzalloc_obj(*mem_tmp); if (!mem_tmp) { kfree(pfmem[count]); return -ENOMEM; } mem_tmp->type = MEM; mem_tmp->busno = pfmem[count]->busno; mem_tmp->devfunc = pfmem[count]->devfunc; mem_tmp->len = pfmem[count]->len; debug("there's no pfmem... going into mem.\n"); if (ibmphp_check_resource(mem_tmp, 0) == 0) { ibmphp_add_resource(mem_tmp); pfmem[count]->fromMem = 1; pfmem[count]->rangeno = mem_tmp->rangeno; pfmem[count]->start = mem_tmp->start; pfmem[count]->end = mem_tmp->end; ibmphp_add_pfmem_from_mem(pfmem[count]); func->pfmem[count] = pfmem[count]; } else { err("cannot allocate requested pfmem for bus %x, device %x, len %x\n", func->busno, func->device, len[count]); kfree(mem_tmp); kfree(pfmem[count]); return -EIO; } } pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], func->pfmem[count]->start); /*_______________This is for debugging purposes only______________________________*/ debug("b4 writing, start address is %x\n", func->pfmem[count]->start); pci_bus_read_config_dword(ibmphp_pci_bus, devfn, address[count], &bar[count]); debug("after writing, start address is %x\n", bar[count]); /*_________________________________________________________________________________*/ if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ debug("inside the mem 64 case, count %d\n", count); count += 1; /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], 0x00000000); } } else { /* regular memory */ debug("REGULAR MEM SPACE\n"); len[count] = bar[count] & 0xFFFFFFF0; len[count] = ~len[count] + 1; debug("len[count] in Mem %x, count %d\n", len[count], count); mem[count] = kzalloc_obj(struct resource_node); if (!mem[count]) return -ENOMEM; mem[count]->type = MEM; mem[count]->busno = func->busno; mem[count]->devfunc = PCI_DEVFN(func->device, func->function); mem[count]->len = len[count]; if (ibmphp_check_resource(mem[count], 0) == 0) { ibmphp_add_resource(mem[count]); func->mem[count] = mem[count]; } else {Lines 1–500 of 1689. Load more
// SPDX-License-Identifier: GPL-2.0+ /* * IBM Hot Plug Controller Driver * * Written By: Irene Zubarev, IBM Corporation * * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2001,2002 IBM Corp. * * All rights reserved. * * Send feedback to <gregkh@us.ibm.com> * */ #include <linux/module.h> #include <linux/slab.h> #include <linux/pci.h> #include <linux/list.h> #include "ibmphp.h" static int configure_device(struct pci_func *); static int configure_bridge(struct pci_func **, u8); static struct res_needed *scan_behind_bridge(struct pci_func *, u8); static int add_new_bus(struct bus_node *, struct resource_node *, struct resource_node *, struct resource_node *, u8); static u8 find_sec_number(u8 primary_busno, u8 slotno); /* * NOTE..... If BIOS doesn't provide default routing, we assign: * 9 for SCSI, 10 for LAN adapters, and 11 for everything else. * If adapter is bridged, then we assign 11 to it and devices behind it. * We also assign the same irq numbers for multi function devices. * These are PIC mode, so shouldn't matter n.e.ways (hopefully) */ static void assign_alt_irq(struct pci_func *cur_func, u8 class_code) { int j; for (j = 0; j < 4; j++) { if (cur_func->irq[j] == 0xff) { switch (class_code) { case PCI_BASE_CLASS_STORAGE: cur_func->irq[j] = SCSI_IRQ; break; case PCI_BASE_CLASS_NETWORK: cur_func->irq[j] = LAN_IRQ; break; default: cur_func->irq[j] = OTHER_IRQ; break; } } } } /* * Configures the device to be added (will allocate needed resources if it * can), the device can be a bridge or a regular pci device, can also be * multi-functional * * Input: function to be added * * TO DO: The error case with Multifunction device or multi function bridge, * if there is an error, will need to go through all previous functions and * unconfigure....or can add some code into unconfigure_card.... */ int ibmphp_configure_card(struct pci_func *func, u8 slotno) { u16 vendor_id; u32 class; u8 class_code; u8 hdr_type, device, sec_number; u8 function; struct pci_func *newfunc; /* for multi devices */ struct pci_func *cur_func, *prev_func; int rc, i, j; int cleanup_count; u8 flag; u8 valid_device = 0x00; /* to see if we are able to read from card any device info at all */ debug("inside configure_card, func->busno = %x\n", func->busno); device = func->device; cur_func = func; /* We only get bus and device from IRQ routing table. So at this point, * func->busno is correct, and func->device contains only device (at the 5 * highest bits) */ /* For every function on the card */ for (function = 0x00; function < 0x08; function++) { unsigned int devfn = PCI_DEVFN(device, function); ibmphp_pci_bus->number = cur_func->busno; cur_func->function = function; debug("inside the loop, cur_func->busno = %x, cur_func->device = %x, cur_func->function = %x\n", cur_func->busno, cur_func->device, cur_func->function); pci_bus_read_config_word(ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id); debug("vendor_id is %x\n", vendor_id); if (vendor_id != PCI_VENDOR_ID_NOTVALID) { /* found correct device!!! */ debug("found valid device, vendor_id = %x\n", vendor_id); ++valid_device; /* header: x x x x x x x x * | |___________|=> 1=PPB bridge, 0=normal device, 2=CardBus Bridge * |_=> 0 = single function device, 1 = multi-function device */ pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type); pci_bus_read_config_dword(ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class); class_code = class >> 24; debug("hrd_type = %x, class = %x, class_code %x\n", hdr_type, class, class_code); class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ if (class == PCI_CLASS_NOT_DEFINED_VGA) { err("The device %x is VGA compatible and as is not supported for hot plugging. " "Please choose another device.\n", cur_func->device); return -ENODEV; } else if (class == PCI_CLASS_DISPLAY_VGA) { err("The device %x is not supported for hot plugging. Please choose another device.\n", cur_func->device); return -ENODEV; } switch (hdr_type) { case PCI_HEADER_TYPE_NORMAL: debug("single device case.... vendor id = %x, hdr_type = %x, class = %x\n", vendor_id, hdr_type, class); assign_alt_irq(cur_func, class_code); rc = configure_device(cur_func); if (rc < 0) { /* We need to do this in case some other BARs were properly inserted */ err("was not able to configure devfunc %x on bus %x.\n", cur_func->device, cur_func->busno); cleanup_count = 6; goto error; } cur_func->next = NULL; function = 0x8; break; case PCI_HEADER_TYPE_MULTIDEVICE: assign_alt_irq(cur_func, class_code); rc = configure_device(cur_func); if (rc < 0) { /* We need to do this in case some other BARs were properly inserted */ err("was not able to configure devfunc %x on bus %x...bailing out\n", cur_func->device, cur_func->busno); cleanup_count = 6; goto error; } newfunc = kzalloc_obj(*newfunc); if (!newfunc) return -ENOMEM; newfunc->busno = cur_func->busno; newfunc->device = device; cur_func->next = newfunc; cur_func = newfunc; for (j = 0; j < 4; j++) newfunc->irq[j] = cur_func->irq[j]; break; case PCI_HEADER_TYPE_MULTIBRIDGE: class >>= 8; if (class != PCI_CLASS_BRIDGE_PCI) { err("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. Please insert another card.\n", cur_func->device); return -ENODEV; } assign_alt_irq(cur_func, class_code); rc = configure_bridge(&cur_func, slotno); if (rc == -ENODEV) { err("You chose to insert Single Bridge, or nested bridges, this is not supported...\n"); err("Bus %x, devfunc %x\n", cur_func->busno, cur_func->device); return rc; } if (rc) { /* We need to do this in case some other BARs were properly inserted */ err("was not able to hot-add PPB properly.\n"); func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ cleanup_count = 2; goto error; } pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); flag = 0; for (i = 0; i < 32; i++) { if (func->devices[i]) { newfunc = kzalloc_obj(*newfunc); if (!newfunc) return -ENOMEM; newfunc->busno = sec_number; newfunc->device = (u8) i; for (j = 0; j < 4; j++) newfunc->irq[j] = cur_func->irq[j]; if (flag) { for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ; prev_func->next = newfunc; } else cur_func->next = newfunc; rc = ibmphp_configure_card(newfunc, slotno); /* This could only happen if kmalloc failed */ if (rc) { /* We need to do this in case bridge itself got configured properly, but devices behind it failed */ func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ cleanup_count = 2; goto error; } flag = 1; } } newfunc = kzalloc_obj(*newfunc); if (!newfunc) return -ENOMEM; newfunc->busno = cur_func->busno; newfunc->device = device; for (j = 0; j < 4; j++) newfunc->irq[j] = cur_func->irq[j]; for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next); prev_func->next = newfunc; cur_func = newfunc; break; case PCI_HEADER_TYPE_BRIDGE: class >>= 8; debug("class now is %x\n", class); if (class != PCI_CLASS_BRIDGE_PCI) { err("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. Please insert another card.\n", cur_func->device); return -ENODEV; } assign_alt_irq(cur_func, class_code); debug("cur_func->busno b4 configure_bridge is %x\n", cur_func->busno); rc = configure_bridge(&cur_func, slotno); if (rc == -ENODEV) { err("You chose to insert Single Bridge, or nested bridges, this is not supported...\n"); err("Bus %x, devfunc %x\n", cur_func->busno, cur_func->device); return rc; } if (rc) { /* We need to do this in case some other BARs were properly inserted */ func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ err("was not able to hot-add PPB properly.\n"); cleanup_count = 2; goto error; } debug("cur_func->busno = %x, device = %x, function = %x\n", cur_func->busno, device, function); pci_bus_read_config_byte(ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); debug("after configuring bridge..., sec_number = %x\n", sec_number); flag = 0; for (i = 0; i < 32; i++) { if (func->devices[i]) { debug("inside for loop, device is %x\n", i); newfunc = kzalloc_obj(*newfunc); if (!newfunc) return -ENOMEM; newfunc->busno = sec_number; newfunc->device = (u8) i; for (j = 0; j < 4; j++) newfunc->irq[j] = cur_func->irq[j]; if (flag) { for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next); prev_func->next = newfunc; } else cur_func->next = newfunc; rc = ibmphp_configure_card(newfunc, slotno); /* Again, this case should not happen... For complete paranoia, will need to call remove_bus */ if (rc) { /* We need to do this in case some other BARs were properly inserted */ func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ cleanup_count = 2; goto error; } flag = 1; } } function = 0x8; break; default: err("MAJOR PROBLEM!!!!, header type not supported? %x\n", hdr_type); return -ENXIO; } /* end of switch */ } /* end of valid device */ } /* end of for */ if (!valid_device) { err("Cannot find any valid devices on the card. Or unable to read from card.\n"); return -ENODEV; } return 0; error: for (i = 0; i < cleanup_count; i++) { if (cur_func->io[i]) { ibmphp_remove_resource(cur_func->io[i]); cur_func->io[i] = NULL; } else if (cur_func->pfmem[i]) { ibmphp_remove_resource(cur_func->pfmem[i]); cur_func->pfmem[i] = NULL; } else if (cur_func->mem[i]) { ibmphp_remove_resource(cur_func->mem[i]); cur_func->mem[i] = NULL; } } return rc; } /* * This function configures the pci BARs of a single device. * Input: pointer to the pci_func * Output: configured PCI, 0, or error */ static int configure_device(struct pci_func *func) { u32 bar[6]; static const u32 address[] = { PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2, PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5, 0 }; u8 irq; int count; int len[6]; struct resource_node *io[6]; struct resource_node *mem[6]; struct resource_node *mem_tmp; struct resource_node *pfmem[6]; unsigned int devfn; debug("%s - inside\n", __func__); devfn = PCI_DEVFN(func->device, func->function); ibmphp_pci_bus->number = func->busno; for (count = 0; address[count]; count++) { /* for 6 BARs */ /* not sure if i need this. per scott, said maybe need * something like this if devices don't adhere 100% to the spec, so don't want to write to the reserved bits pcibios_read_config_byte(cur_func->busno, cur_func->device, PCI_BASE_ADDRESS_0 + 4 * count, &tmp); if (tmp & 0x01) // IO pcibios_write_config_dword(cur_func->busno, cur_func->device, PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFD); else // Memory pcibios_write_config_dword(cur_func->busno, cur_func->device, PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFF); */ pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF); pci_bus_read_config_dword(ibmphp_pci_bus, devfn, address[count], &bar[count]); if (!bar[count]) /* This BAR is not implemented */ continue; debug("Device %x BAR %d wants %x\n", func->device, count, bar[count]); if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) { /* This is IO */ debug("inside IO SPACE\n"); len[count] = bar[count] & 0xFFFFFFFC; len[count] = ~len[count] + 1; debug("len[count] in IO %x, count %d\n", len[count], count); io[count] = kzalloc_obj(struct resource_node); if (!io[count]) return -ENOMEM; io[count]->type = IO; io[count]->busno = func->busno; io[count]->devfunc = PCI_DEVFN(func->device, func->function); io[count]->len = len[count]; if (ibmphp_check_resource(io[count], 0) == 0) { ibmphp_add_resource(io[count]); func->io[count] = io[count]; } else { err("cannot allocate requested io for bus %x device %x function %x len %x\n", func->busno, func->device, func->function, len[count]); kfree(io[count]); return -EIO; } pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], func->io[count]->start); /* _______________This is for debugging purposes only_____________________ */ debug("b4 writing, the IO address is %x\n", func->io[count]->start); pci_bus_read_config_dword(ibmphp_pci_bus, devfn, address[count], &bar[count]); debug("after writing.... the start address is %x\n", bar[count]); /* _________________________________________________________________________*/ } else { /* This is Memory */ if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) { /* pfmem */ debug("PFMEM SPACE\n"); len[count] = bar[count] & 0xFFFFFFF0; len[count] = ~len[count] + 1; debug("len[count] in PFMEM %x, count %d\n", len[count], count); pfmem[count] = kzalloc_obj(struct resource_node); if (!pfmem[count]) return -ENOMEM; pfmem[count]->type = PFMEM; pfmem[count]->busno = func->busno; pfmem[count]->devfunc = PCI_DEVFN(func->device, func->function); pfmem[count]->len = len[count]; pfmem[count]->fromMem = 0; if (ibmphp_check_resource(pfmem[count], 0) == 0) { ibmphp_add_resource(pfmem[count]); func->pfmem[count] = pfmem[count]; } else { mem_tmp = kzalloc_obj(*mem_tmp); if (!mem_tmp) { kfree(pfmem[count]); return -ENOMEM; } mem_tmp->type = MEM; mem_tmp->busno = pfmem[count]->busno; mem_tmp->devfunc = pfmem[count]->devfunc; mem_tmp->len = pfmem[count]->len; debug("there's no pfmem... going into mem.\n"); if (ibmphp_check_resource(mem_tmp, 0) == 0) { ibmphp_add_resource(mem_tmp); pfmem[count]->fromMem = 1; pfmem[count]->rangeno = mem_tmp->rangeno; pfmem[count]->start = mem_tmp->start; pfmem[count]->end = mem_tmp->end; ibmphp_add_pfmem_from_mem(pfmem[count]); func->pfmem[count] = pfmem[count]; } else { err("cannot allocate requested pfmem for bus %x, device %x, len %x\n", func->busno, func->device, len[count]); kfree(mem_tmp); kfree(pfmem[count]); return -EIO; } } pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], func->pfmem[count]->start); /*_______________This is for debugging purposes only______________________________*/ debug("b4 writing, start address is %x\n", func->pfmem[count]->start); pci_bus_read_config_dword(ibmphp_pci_bus, devfn, address[count], &bar[count]); debug("after writing, start address is %x\n", bar[count]); /*_________________________________________________________________________________*/ if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ debug("inside the mem 64 case, count %d\n", count); count += 1; /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ pci_bus_write_config_dword(ibmphp_pci_bus, devfn, address[count], 0x00000000); } } else { /* regular memory */ debug("REGULAR MEM SPACE\n"); len[count] = bar[count] & 0xFFFFFFF0; len[count] = ~len[count] + 1; debug("len[count] in Mem %x, count %d\n", len[count], count); mem[count] = kzalloc_obj(struct resource_node); if (!mem[count]) return -ENOMEM; mem[count]->type = MEM; mem[count]->busno = func->busno; mem[count]->devfunc = PCI_DEVFN(func->device, func->function); mem[count]->len = len[count]; if (ibmphp_check_resource(mem[count], 0) == 0) { ibmphp_add_resource(mem[count]); func->mem[count] = mem[count]; } else {