in hotplug/cpqphp_ctrl.c [1405:1601]
static u32 board_added(struct pci_func *func, struct controller *ctrl)
{
u8 hp_slot;
u8 temp_byte;
u8 adapter_speed;
int index;
u32 temp_register = 0xFFFFFFFF;
u32 rc = 0;
struct pci_func *new_slot = NULL;
struct pci_bus *bus = ctrl->pci_bus;
struct slot *p_slot;
struct resource_lists res_lists;
hp_slot = func->device - ctrl->slot_device_offset;
dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n",
__func__, func->device, ctrl->slot_device_offset, hp_slot);
mutex_lock(&ctrl->crit_sect);
/* turn on board without attaching to the bus */
enable_slot_power(ctrl, hp_slot);
set_SOGO(ctrl);
/* Wait for SOBS to be unset */
wait_for_ctrl_irq(ctrl);
/* Change bits in slot power register to force another shift out
* NOTE: this is to work around the timer bug
*/
temp_byte = readb(ctrl->hpc_reg + SLOT_POWER);
writeb(0x00, ctrl->hpc_reg + SLOT_POWER);
writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER);
set_SOGO(ctrl);
/* Wait for SOBS to be unset */
wait_for_ctrl_irq(ctrl);
adapter_speed = get_adapter_speed(ctrl, hp_slot);
if (bus->cur_bus_speed != adapter_speed)
if (set_controller_speed(ctrl, adapter_speed, hp_slot))
rc = WRONG_BUS_FREQUENCY;
/* turn off board without attaching to the bus */
disable_slot_power(ctrl, hp_slot);
set_SOGO(ctrl);
/* Wait for SOBS to be unset */
wait_for_ctrl_irq(ctrl);
mutex_unlock(&ctrl->crit_sect);
if (rc)
return rc;
p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
/* turn on board and blink green LED */
dbg("%s: before down\n", __func__);
mutex_lock(&ctrl->crit_sect);
dbg("%s: after down\n", __func__);
dbg("%s: before slot_enable\n", __func__);
slot_enable(ctrl, hp_slot);
dbg("%s: before green_LED_blink\n", __func__);
green_LED_blink(ctrl, hp_slot);
dbg("%s: before amber_LED_blink\n", __func__);
amber_LED_off(ctrl, hp_slot);
dbg("%s: before set_SOGO\n", __func__);
set_SOGO(ctrl);
/* Wait for SOBS to be unset */
dbg("%s: before wait_for_ctrl_irq\n", __func__);
wait_for_ctrl_irq(ctrl);
dbg("%s: after wait_for_ctrl_irq\n", __func__);
dbg("%s: before up\n", __func__);
mutex_unlock(&ctrl->crit_sect);
dbg("%s: after up\n", __func__);
/* Wait for ~1 second because of hot plug spec */
dbg("%s: before long_delay\n", __func__);
long_delay(1*HZ);
dbg("%s: after long_delay\n", __func__);
dbg("%s: func status = %x\n", __func__, func->status);
/* Check for a power fault */
if (func->status == 0xFF) {
/* power fault occurred, but it was benign */
temp_register = 0xFFFFFFFF;
dbg("%s: temp register set to %x by power fault\n", __func__, temp_register);
rc = POWER_FAILURE;
func->status = 0;
} else {
/* Get vendor/device ID u32 */
ctrl->pci_bus->number = func->bus;
rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(func->device, func->function), PCI_VENDOR_ID, &temp_register);
dbg("%s: pci_read_config_dword returns %d\n", __func__, rc);
dbg("%s: temp_register is %x\n", __func__, temp_register);
if (rc != 0) {
/* Something's wrong here */
temp_register = 0xFFFFFFFF;
dbg("%s: temp register set to %x by error\n", __func__, temp_register);
}
/* Preset return code. It will be changed later if things go okay. */
rc = NO_ADAPTER_PRESENT;
}
/* All F's is an empty slot or an invalid board */
if (temp_register != 0xFFFFFFFF) {
res_lists.io_head = ctrl->io_head;
res_lists.mem_head = ctrl->mem_head;
res_lists.p_mem_head = ctrl->p_mem_head;
res_lists.bus_head = ctrl->bus_head;
res_lists.irqs = NULL;
rc = configure_new_device(ctrl, func, 0, &res_lists);
dbg("%s: back from configure_new_device\n", __func__);
ctrl->io_head = res_lists.io_head;
ctrl->mem_head = res_lists.mem_head;
ctrl->p_mem_head = res_lists.p_mem_head;
ctrl->bus_head = res_lists.bus_head;
cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
cpqhp_resource_sort_and_combine(&(ctrl->io_head));
cpqhp_resource_sort_and_combine(&(ctrl->bus_head));
if (rc) {
mutex_lock(&ctrl->crit_sect);
amber_LED_on(ctrl, hp_slot);
green_LED_off(ctrl, hp_slot);
slot_disable(ctrl, hp_slot);
set_SOGO(ctrl);
/* Wait for SOBS to be unset */
wait_for_ctrl_irq(ctrl);
mutex_unlock(&ctrl->crit_sect);
return rc;
} else {
cpqhp_save_slot_config(ctrl, func);
}
func->status = 0;
func->switch_save = 0x10;
func->is_a_board = 0x01;
/* next, we will instantiate the linux pci_dev structures (with
* appropriate driver notification, if already present) */
dbg("%s: configure linux pci_dev structure\n", __func__);
index = 0;
do {
new_slot = cpqhp_slot_find(ctrl->bus, func->device, index++);
if (new_slot && !new_slot->pci_dev)
cpqhp_configure_device(ctrl, new_slot);
} while (new_slot);
mutex_lock(&ctrl->crit_sect);
green_LED_on(ctrl, hp_slot);
set_SOGO(ctrl);
/* Wait for SOBS to be unset */
wait_for_ctrl_irq(ctrl);
mutex_unlock(&ctrl->crit_sect);
} else {
mutex_lock(&ctrl->crit_sect);
amber_LED_on(ctrl, hp_slot);
green_LED_off(ctrl, hp_slot);
slot_disable(ctrl, hp_slot);
set_SOGO(ctrl);
/* Wait for SOBS to be unset */
wait_for_ctrl_irq(ctrl);
mutex_unlock(&ctrl->crit_sect);
return rc;
}
return 0;
}