// SPDX-License-Identifier: GPL-2.0+/* * Compaq Hot Plug Controller Driver * * Copyright (C) 1995,2001 Compaq Computer Corporation * Copyright (C) 2001 Greg Kroah-Hartman <greg@kroah.com> * Copyright (C) 2001 IBM Corp. * * All rights reserved. * * Send feedback to <greg@kroah.com> * * Jan 12, 2003 - Added 66/100/133MHz PCI-X support, * Torben Mathiasen <torben.mathiasen@hp.com> */ #include <linux/module.h>#include <linux/moduleparam.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/proc_fs.h>#include <linux/slab.h>#include <linux/workqueue.h>#include <linux/pci.h>#include <linux/pci_hotplug.h>#include <linux/init.h>#include <linux/interrupt.h> #include <linux/uaccess.h> #include "cpqphp.h"#include "cpqphp_nvram.h" /* Global variables */int cpqhp_debug;int cpqhp_legacy_mode;struct controller *cpqhp_ctrl_list; /* = NULL */struct pci_func *cpqhp_slot_list[256];struct irq_routing_table *cpqhp_routing_table; /* local variables */static void __iomem *smbios_table;static void __iomem *smbios_start;static void __iomem *cpqhp_rom_start;static bool power_mode;static bool debug;static int initialized; #define DRIVER_VERSION "0.9.8"#define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>"#define DRIVER_DESC "Compaq Hot Plug PCI Controller Driver" MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL"); module_param(power_mode, bool, 0644);MODULE_PARM_DESC(power_mode, "Power mode enabled or not"); module_param(debug, bool, 0644);MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); #define CPQHPC_MODULE_MINOR 208 static inline int is_slot64bit(struct slot *slot){ return (readb(slot->p_sm_slot + SMBIOS_SLOT_WIDTH) == 0x06) ? 1 : 0;} static inline int is_slot66mhz(struct slot *slot){ return (readb(slot->p_sm_slot + SMBIOS_SLOT_TYPE) == 0x0E) ? 1 : 0;} /** * detect_SMBIOS_pointer - find the System Management BIOS Table in mem region. * @begin: begin pointer for region to be scanned. * @end: end pointer for region to be scanned. * * Returns pointer to the head of the SMBIOS tables (or %NULL). */static void __iomem *detect_SMBIOS_pointer(void __iomem *begin, void __iomem *end){ void __iomem *fp; void __iomem *endp; u8 temp1, temp2, temp3, temp4; int status = 0; endp = (end - sizeof(u32) + 1); for (fp = begin; fp <= endp; fp += 16) { temp1 = readb(fp); temp2 = readb(fp+1); temp3 = readb(fp+2); temp4 = readb(fp+3); if (temp1 == '_' && temp2 == 'S' && temp3 == 'M' && temp4 == '_') { status = 1; break; } } if (!status) fp = NULL; dbg("Discovered SMBIOS Entry point at %p\n", fp); return fp;} /** * init_SERR - Initializes the per slot SERR generation. * @ctrl: controller to use * * For unexpected switch opens */static int init_SERR(struct controller *ctrl){ u32 tempdword; u32 number_of_slots; if (!ctrl) return 1; tempdword = ctrl->first_slot; number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; /* Loop through slots */ while (number_of_slots) { writeb(0, ctrl->hpc_reg + SLOT_SERR); tempdword++; number_of_slots--; } return 0;} static int init_cpqhp_routing_table(void){ int len; cpqhp_routing_table = pcibios_get_irq_routing_table(); if (cpqhp_routing_table == NULL) return -ENOMEM; len = cpqhp_routing_table_length(); if (len == 0) { kfree(cpqhp_routing_table); cpqhp_routing_table = NULL; return -1; } return 0;} /* nice debugging output */static void pci_print_IRQ_route(void){ int len; int loop; u8 tbus, tdevice, tslot; len = cpqhp_routing_table_length(); dbg("bus dev func slot\n"); for (loop = 0; loop < len; ++loop) { tbus = cpqhp_routing_table->slots[loop].bus; tdevice = cpqhp_routing_table->slots[loop].devfn; tslot = cpqhp_routing_table->slots[loop].slot; dbg("%d %d %d %d\n", tbus, tdevice >> 3, tdevice & 0x7, tslot); }} /** * get_subsequent_smbios_entry: get the next entry from bios table. * @smbios_start: where to start in the SMBIOS table * @smbios_table: location of the SMBIOS table * @curr: %NULL or pointer to previously returned structure * * Gets the first entry if previous == NULL; * otherwise, returns the next entry. * Uses global SMBIOS Table pointer. * * Returns a pointer to an SMBIOS structure or NULL if none found. */static void __iomem *get_subsequent_smbios_entry(void __iomem *smbios_start, void __iomem *smbios_table, void __iomem *curr){ u8 bail = 0; u8 previous_byte = 1; void __iomem *p_temp; void __iomem *p_max; if (!smbios_table || !curr) return NULL; /* set p_max to the end of the table */ p_max = smbios_start + readw(smbios_table + ST_LENGTH); p_temp = curr; p_temp += readb(curr + SMBIOS_GENERIC_LENGTH); while ((p_temp < p_max) && !bail) { /* Look for the double NULL terminator * The first condition is the previous byte * and the second is the curr */ if (!previous_byte && !(readb(p_temp))) bail = 1; previous_byte = readb(p_temp); p_temp++; } if (p_temp < p_max) return p_temp; else return NULL;} /** * get_SMBIOS_entry - return the requested SMBIOS entry or %NULL * @smbios_start: where to start in the SMBIOS table * @smbios_table: location of the SMBIOS table * @type: SMBIOS structure type to be returned * @previous: %NULL or pointer to previously returned structure * * Gets the first entry of the specified type if previous == %NULL; * Otherwise, returns the next entry of the given type. * Uses global SMBIOS Table pointer. * Uses get_subsequent_smbios_entry. * * Returns a pointer to an SMBIOS structure or %NULL if none found. */static void __iomem *get_SMBIOS_entry(void __iomem *smbios_start, void __iomem *smbios_table, u8 type, void __iomem *previous){ if (!smbios_table) return NULL; if (!previous) previous = smbios_start; else previous = get_subsequent_smbios_entry(smbios_start, smbios_table, previous); while (previous) if (readb(previous + SMBIOS_GENERIC_TYPE) != type) previous = get_subsequent_smbios_entry(smbios_start, smbios_table, previous); else break; return previous;} static int ctrl_slot_cleanup(struct controller *ctrl){ struct slot *old_slot, *next_slot; old_slot = ctrl->slot; ctrl->slot = NULL; while (old_slot) { next_slot = old_slot->next; pci_hp_deregister(&old_slot->hotplug_slot); kfree(old_slot); old_slot = next_slot; } cpqhp_remove_debugfs_files(ctrl); /* Free IRQ associated with hot plug device */ free_irq(ctrl->interrupt, ctrl); /* Unmap the memory */ iounmap(ctrl->hpc_reg); /* Finally reclaim PCI mem */ release_mem_region(pci_resource_start(ctrl->pci_dev, 0), pci_resource_len(ctrl->pci_dev, 0)); return 0;} /** * get_slot_mapping - determine logical slot mapping for PCI device * * Won't work for more than one PCI-PCI bridge in a slot. * * @bus: pointer to the PCI bus structure * @bus_num: bus number of PCI device * @dev_num: device number of PCI device * @slot: Pointer to u8 where slot number will be returned * * Output: SUCCESS or FAILURE */static intget_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot){ u32 work; long len; long loop; u8 tbus, tdevice, tslot, bridgeSlot; dbg("%s: %p, %d, %d, %p\n", __func__, bus, bus_num, dev_num, slot); bridgeSlot = 0xFF; len = cpqhp_routing_table_length(); for (loop = 0; loop < len; ++loop) { tbus = cpqhp_routing_table->slots[loop].bus; tdevice = cpqhp_routing_table->slots[loop].devfn >> 3; tslot = cpqhp_routing_table->slots[loop].slot; if ((tbus == bus_num) && (tdevice == dev_num)) { *slot = tslot; return 0; } else { /* Did not get a match on the target PCI device. Check * if the current IRQ table entry is a PCI-to-PCI * bridge device. If so, and its secondary bus * matches the bus number for the target device, I need * to save the bridge's slot number. If I can not find * an entry for the target device, I will have to * assume it's on the other side of the bridge, and * assign it the bridge's slot. */ bus->number = tbus; pci_bus_read_config_dword(bus, PCI_DEVFN(tdevice, 0), PCI_CLASS_REVISION, &work); if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { pci_bus_read_config_dword(bus, PCI_DEVFN(tdevice, 0), PCI_PRIMARY_BUS, &work); // See if bridge's secondary bus matches target bus. if (((work >> 8) & 0x000000FF) == (long) bus_num) bridgeSlot = tslot; } } } /* If we got here, we didn't find an entry in the IRQ mapping table for * the target PCI device. If we did determine that the target device * is on the other side of a PCI-to-PCI bridge, return the slot number * for the bridge. */ if (bridgeSlot != 0xFF) { *slot = bridgeSlot; return 0; } /* Couldn't find an entry in the routing table for this PCI device */ return -1;} /** * cpqhp_set_attention_status - Turns the Amber LED for a slot on or off * @ctrl: struct controller to use * @func: PCI device/function info * @status: LED control flag: 1 = LED on, 0 = LED off */static intcpqhp_set_attention_status(struct controller *ctrl, struct pci_func *func, u32 status){ u8 hp_slot; if (func == NULL) return 1; hp_slot = func->device - ctrl->slot_device_offset; /* Wait for exclusive access to hardware */ mutex_lock(&ctrl->crit_sect); if (status == 1) amber_LED_on(ctrl, hp_slot); else if (status == 0) amber_LED_off(ctrl, hp_slot); else { /* Done with exclusive hardware access */ mutex_unlock(&ctrl->crit_sect); return 1; } set_SOGO(ctrl); /* Wait for SOBS to be unset */ wait_for_ctrl_irq(ctrl); /* Done with exclusive hardware access */ mutex_unlock(&ctrl->crit_sect); return 0;} /** * set_attention_status - Turns the Amber LED for a slot on or off * @hotplug_slot: slot to change LED on * @status: LED control flag */static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status){ struct pci_func *slot_func; struct slot *slot = to_slot(hotplug_slot); struct controller *ctrl = slot->ctrl; u8 bus; u8 devfn; u8 device; u8 function; dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) return -ENODEV; device = devfn >> 3; function = devfn & 0x7; dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); slot_func = cpqhp_slot_find(bus, device, function); if (!slot_func) return -ENODEV; return cpqhp_set_attention_status(ctrl, slot_func, status);} static int process_SI(struct hotplug_slot *hotplug_slot){ struct pci_func *slot_func; struct slot *slot = to_slot(hotplug_slot); struct controller *ctrl = slot->ctrl; u8 bus; u8 devfn; u8 device; u8 function; dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) return -ENODEV; device = devfn >> 3; function = devfn & 0x7; dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); slot_func = cpqhp_slot_find(bus, device, function); if (!slot_func) return -ENODEV; slot_func->bus = bus; slot_func->device = device; slot_func->function = function; slot_func->configured = 0; dbg("board_added(%p, %p)\n", slot_func, ctrl); return cpqhp_process_SI(ctrl, slot_func);} static int process_SS(struct hotplug_slot *hotplug_slot){ struct pci_func *slot_func; struct slot *slot = to_slot(hotplug_slot); struct controller *ctrl = slot->ctrl; u8 bus; u8 devfn; u8 device; u8 function; dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) return -ENODEV; device = devfn >> 3; function = devfn & 0x7; dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); slot_func = cpqhp_slot_find(bus, device, function); if (!slot_func) return -ENODEV; dbg("In %s, slot_func = %p, ctrl = %p\n", __func__, slot_func, ctrl); return cpqhp_process_SS(ctrl, slot_func);} Lines 1–500 of 1407. Load more
// SPDX-License-Identifier: GPL-2.0+ /* * Compaq Hot Plug Controller Driver * * Copyright (C) 1995,2001 Compaq Computer Corporation * Copyright (C) 2001 Greg Kroah-Hartman <greg@kroah.com> * Copyright (C) 2001 IBM Corp. * * All rights reserved. * * Send feedback to <greg@kroah.com> * * Jan 12, 2003 - Added 66/100/133MHz PCI-X support, * Torben Mathiasen <torben.mathiasen@hp.com> */ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/proc_fs.h> #include <linux/slab.h> #include <linux/workqueue.h> #include <linux/pci.h> #include <linux/pci_hotplug.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/uaccess.h> #include "cpqphp.h" #include "cpqphp_nvram.h" /* Global variables */ int cpqhp_debug; int cpqhp_legacy_mode; struct controller *cpqhp_ctrl_list; /* = NULL */ struct pci_func *cpqhp_slot_list[256]; struct irq_routing_table *cpqhp_routing_table; /* local variables */ static void __iomem *smbios_table; static void __iomem *smbios_start; static void __iomem *cpqhp_rom_start; static bool power_mode; static bool debug; static int initialized; #define DRIVER_VERSION "0.9.8" #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>" #define DRIVER_DESC "Compaq Hot Plug PCI Controller Driver" MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); module_param(power_mode, bool, 0644); MODULE_PARM_DESC(power_mode, "Power mode enabled or not"); module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); #define CPQHPC_MODULE_MINOR 208 static inline int is_slot64bit(struct slot *slot) { return (readb(slot->p_sm_slot + SMBIOS_SLOT_WIDTH) == 0x06) ? 1 : 0; } static inline int is_slot66mhz(struct slot *slot) { return (readb(slot->p_sm_slot + SMBIOS_SLOT_TYPE) == 0x0E) ? 1 : 0; } /** * detect_SMBIOS_pointer - find the System Management BIOS Table in mem region. * @begin: begin pointer for region to be scanned. * @end: end pointer for region to be scanned. * * Returns pointer to the head of the SMBIOS tables (or %NULL). */ static void __iomem *detect_SMBIOS_pointer(void __iomem *begin, void __iomem *end) { void __iomem *fp; void __iomem *endp; u8 temp1, temp2, temp3, temp4; int status = 0; endp = (end - sizeof(u32) + 1); for (fp = begin; fp <= endp; fp += 16) { temp1 = readb(fp); temp2 = readb(fp+1); temp3 = readb(fp+2); temp4 = readb(fp+3); if (temp1 == '_' && temp2 == 'S' && temp3 == 'M' && temp4 == '_') { status = 1; break; } } if (!status) fp = NULL; dbg("Discovered SMBIOS Entry point at %p\n", fp); return fp; } /** * init_SERR - Initializes the per slot SERR generation. * @ctrl: controller to use * * For unexpected switch opens */ static int init_SERR(struct controller *ctrl) { u32 tempdword; u32 number_of_slots; if (!ctrl) return 1; tempdword = ctrl->first_slot; number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; /* Loop through slots */ while (number_of_slots) { writeb(0, ctrl->hpc_reg + SLOT_SERR); tempdword++; number_of_slots--; } return 0; } static int init_cpqhp_routing_table(void) { int len; cpqhp_routing_table = pcibios_get_irq_routing_table(); if (cpqhp_routing_table == NULL) return -ENOMEM; len = cpqhp_routing_table_length(); if (len == 0) { kfree(cpqhp_routing_table); cpqhp_routing_table = NULL; return -1; } return 0; } /* nice debugging output */ static void pci_print_IRQ_route(void) { int len; int loop; u8 tbus, tdevice, tslot; len = cpqhp_routing_table_length(); dbg("bus dev func slot\n"); for (loop = 0; loop < len; ++loop) { tbus = cpqhp_routing_table->slots[loop].bus; tdevice = cpqhp_routing_table->slots[loop].devfn; tslot = cpqhp_routing_table->slots[loop].slot; dbg("%d %d %d %d\n", tbus, tdevice >> 3, tdevice & 0x7, tslot); } } /** * get_subsequent_smbios_entry: get the next entry from bios table. * @smbios_start: where to start in the SMBIOS table * @smbios_table: location of the SMBIOS table * @curr: %NULL or pointer to previously returned structure * * Gets the first entry if previous == NULL; * otherwise, returns the next entry. * Uses global SMBIOS Table pointer. * * Returns a pointer to an SMBIOS structure or NULL if none found. */ static void __iomem *get_subsequent_smbios_entry(void __iomem *smbios_start, void __iomem *smbios_table, void __iomem *curr) { u8 bail = 0; u8 previous_byte = 1; void __iomem *p_temp; void __iomem *p_max; if (!smbios_table || !curr) return NULL; /* set p_max to the end of the table */ p_max = smbios_start + readw(smbios_table + ST_LENGTH); p_temp = curr; p_temp += readb(curr + SMBIOS_GENERIC_LENGTH); while ((p_temp < p_max) && !bail) { /* Look for the double NULL terminator * The first condition is the previous byte * and the second is the curr */ if (!previous_byte && !(readb(p_temp))) bail = 1; previous_byte = readb(p_temp); p_temp++; } if (p_temp < p_max) return p_temp; else return NULL; } /** * get_SMBIOS_entry - return the requested SMBIOS entry or %NULL * @smbios_start: where to start in the SMBIOS table * @smbios_table: location of the SMBIOS table * @type: SMBIOS structure type to be returned * @previous: %NULL or pointer to previously returned structure * * Gets the first entry of the specified type if previous == %NULL; * Otherwise, returns the next entry of the given type. * Uses global SMBIOS Table pointer. * Uses get_subsequent_smbios_entry. * * Returns a pointer to an SMBIOS structure or %NULL if none found. */ static void __iomem *get_SMBIOS_entry(void __iomem *smbios_start, void __iomem *smbios_table, u8 type, void __iomem *previous) { if (!smbios_table) return NULL; if (!previous) previous = smbios_start; else previous = get_subsequent_smbios_entry(smbios_start, smbios_table, previous); while (previous) if (readb(previous + SMBIOS_GENERIC_TYPE) != type) previous = get_subsequent_smbios_entry(smbios_start, smbios_table, previous); else break; return previous; } static int ctrl_slot_cleanup(struct controller *ctrl) { struct slot *old_slot, *next_slot; old_slot = ctrl->slot; ctrl->slot = NULL; while (old_slot) { next_slot = old_slot->next; pci_hp_deregister(&old_slot->hotplug_slot); kfree(old_slot); old_slot = next_slot; } cpqhp_remove_debugfs_files(ctrl); /* Free IRQ associated with hot plug device */ free_irq(ctrl->interrupt, ctrl); /* Unmap the memory */ iounmap(ctrl->hpc_reg); /* Finally reclaim PCI mem */ release_mem_region(pci_resource_start(ctrl->pci_dev, 0), pci_resource_len(ctrl->pci_dev, 0)); return 0; } /** * get_slot_mapping - determine logical slot mapping for PCI device * * Won't work for more than one PCI-PCI bridge in a slot. * * @bus: pointer to the PCI bus structure * @bus_num: bus number of PCI device * @dev_num: device number of PCI device * @slot: Pointer to u8 where slot number will be returned * * Output: SUCCESS or FAILURE */ static int get_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot) { u32 work; long len; long loop; u8 tbus, tdevice, tslot, bridgeSlot; dbg("%s: %p, %d, %d, %p\n", __func__, bus, bus_num, dev_num, slot); bridgeSlot = 0xFF; len = cpqhp_routing_table_length(); for (loop = 0; loop < len; ++loop) { tbus = cpqhp_routing_table->slots[loop].bus; tdevice = cpqhp_routing_table->slots[loop].devfn >> 3; tslot = cpqhp_routing_table->slots[loop].slot; if ((tbus == bus_num) && (tdevice == dev_num)) { *slot = tslot; return 0; } else { /* Did not get a match on the target PCI device. Check * if the current IRQ table entry is a PCI-to-PCI * bridge device. If so, and its secondary bus * matches the bus number for the target device, I need * to save the bridge's slot number. If I can not find * an entry for the target device, I will have to * assume it's on the other side of the bridge, and * assign it the bridge's slot. */ bus->number = tbus; pci_bus_read_config_dword(bus, PCI_DEVFN(tdevice, 0), PCI_CLASS_REVISION, &work); if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { pci_bus_read_config_dword(bus, PCI_DEVFN(tdevice, 0), PCI_PRIMARY_BUS, &work); // See if bridge's secondary bus matches target bus. if (((work >> 8) & 0x000000FF) == (long) bus_num) bridgeSlot = tslot; } } } /* If we got here, we didn't find an entry in the IRQ mapping table for * the target PCI device. If we did determine that the target device * is on the other side of a PCI-to-PCI bridge, return the slot number * for the bridge. */ if (bridgeSlot != 0xFF) { *slot = bridgeSlot; return 0; } /* Couldn't find an entry in the routing table for this PCI device */ return -1; } /** * cpqhp_set_attention_status - Turns the Amber LED for a slot on or off * @ctrl: struct controller to use * @func: PCI device/function info * @status: LED control flag: 1 = LED on, 0 = LED off */ static int cpqhp_set_attention_status(struct controller *ctrl, struct pci_func *func, u32 status) { u8 hp_slot; if (func == NULL) return 1; hp_slot = func->device - ctrl->slot_device_offset; /* Wait for exclusive access to hardware */ mutex_lock(&ctrl->crit_sect); if (status == 1) amber_LED_on(ctrl, hp_slot); else if (status == 0) amber_LED_off(ctrl, hp_slot); else { /* Done with exclusive hardware access */ mutex_unlock(&ctrl->crit_sect); return 1; } set_SOGO(ctrl); /* Wait for SOBS to be unset */ wait_for_ctrl_irq(ctrl); /* Done with exclusive hardware access */ mutex_unlock(&ctrl->crit_sect); return 0; } /** * set_attention_status - Turns the Amber LED for a slot on or off * @hotplug_slot: slot to change LED on * @status: LED control flag */ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) { struct pci_func *slot_func; struct slot *slot = to_slot(hotplug_slot); struct controller *ctrl = slot->ctrl; u8 bus; u8 devfn; u8 device; u8 function; dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) return -ENODEV; device = devfn >> 3; function = devfn & 0x7; dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); slot_func = cpqhp_slot_find(bus, device, function); if (!slot_func) return -ENODEV; return cpqhp_set_attention_status(ctrl, slot_func, status); } static int process_SI(struct hotplug_slot *hotplug_slot) { struct pci_func *slot_func; struct slot *slot = to_slot(hotplug_slot); struct controller *ctrl = slot->ctrl; u8 bus; u8 devfn; u8 device; u8 function; dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) return -ENODEV; device = devfn >> 3; function = devfn & 0x7; dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); slot_func = cpqhp_slot_find(bus, device, function); if (!slot_func) return -ENODEV; slot_func->bus = bus; slot_func->device = device; slot_func->function = function; slot_func->configured = 0; dbg("board_added(%p, %p)\n", slot_func, ctrl); return cpqhp_process_SI(ctrl, slot_func); } static int process_SS(struct hotplug_slot *hotplug_slot) { struct pci_func *slot_func; struct slot *slot = to_slot(hotplug_slot); struct controller *ctrl = slot->ctrl; u8 bus; u8 devfn; u8 device; u8 function; dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) return -ENODEV; device = devfn >> 3; function = devfn & 0x7; dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); slot_func = cpqhp_slot_find(bus, device, function); if (!slot_func) return -ENODEV; dbg("In %s, slot_func = %p, ctrl = %p\n", __func__, slot_func, ctrl); return cpqhp_process_SS(ctrl, slot_func); }