- struct pci_func *new_slot;
- struct pci_func *next;
-
- new_slot = (struct pci_func *) kmalloc(sizeof(struct pci_func), GFP_KERNEL);
-
- if (new_slot == NULL) {
- return(new_slot);
- }
-
- memset(new_slot, 0, sizeof(struct pci_func));
-
- new_slot->next = NULL;
- new_slot->configured = 1;
-
- if (shpchp_slot_list[busnumber] == NULL) {
- shpchp_slot_list[busnumber] = new_slot;
- } else {
- next = shpchp_slot_list[busnumber];
- while (next->next != NULL)
- next = next->next;
- next->next = new_slot;
- }
- return(new_slot);
-}
-
-
-/*
- * slot_remove - Removes a node from the linked list of slots.
- * @old_slot: slot to remove
- *
- * Returns 0 if successful, !0 otherwise.
- */
-static int slot_remove(struct pci_func * old_slot)
-{
- struct pci_func *next;
-
- if (old_slot == NULL)
- return(1);
-
- next = shpchp_slot_list[old_slot->bus];
-
- if (next == NULL) {
- return(1);
- }
-
- if (next == old_slot) {
- shpchp_slot_list[old_slot->bus] = old_slot->next;
- shpchp_destroy_board_resources(old_slot);
- kfree(old_slot);
- return(0);
- }
-
- while ((next->next != old_slot) && (next->next != NULL)) {
- next = next->next;
- }
-
- if (next->next == old_slot) {
- next->next = old_slot->next;
- shpchp_destroy_board_resources(old_slot);
- kfree(old_slot);
- return(0);
- } else
- return(2);
-}
-
-
-/**
- * bridge_slot_remove - Removes a node from the linked list of slots.
- * @bridge: bridge to remove
- *
- * Returns 0 if successful, !0 otherwise.
- */
-static int bridge_slot_remove(struct pci_func *bridge)
-{
- u8 subordinateBus, secondaryBus;
- u8 tempBus;
- struct pci_func *next;
-
- if (bridge == NULL)
- return(1);
-
- secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF;
- subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF;
-
- for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) {
- next = shpchp_slot_list[tempBus];
-
- while (!slot_remove(next)) {
- next = shpchp_slot_list[tempBus];
- }
- }
-
- next = shpchp_slot_list[bridge->bus];
-
- if (next == NULL) {
- return(1);
- }
-
- if (next == bridge) {
- shpchp_slot_list[bridge->bus] = bridge->next;
- kfree(bridge);
- return(0);
- }
-
- while ((next->next != bridge) && (next->next != NULL)) {
- next = next->next;
- }
-
- if (next->next == bridge) {
- next->next = bridge->next;
- kfree(bridge);
- return(0);
- } else
- return(2);
-}
-
-
-/**
- * shpchp_slot_find - Looks for a node by bus, and device, multiple functions accessed
- * @bus: bus to find
- * @device: device to find
- * @index: is 0 for first function found, 1 for the second...
- *
- * Returns pointer to the node if successful, %NULL otherwise.
- */
-struct pci_func *shpchp_slot_find(u8 bus, u8 device, u8 index)
-{
- int found = -1;
- struct pci_func *func;
-
- func = shpchp_slot_list[bus];
-
- if ((func == NULL) || ((func->device == device) && (index == 0)))
- return(func);
-
- if (func->device == device)
- found++;
-
- while (func->next != NULL) {
- func = func->next;
-
- if (func->device == device)
- found++;
-
- if (found == index)
- return(func);
- }
-
- return(NULL);
-}
-
-static int is_bridge(struct pci_func * func)
-{
- /* Check the header type */
- if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01)
- return 1;
- else
- return 0;
-}
-
-
-/* The following routines constitute the bulk of the
- hotplug controller logic
- */
-
-
-/**
- * board_added - Called after a board has been added to the system.
- *
- * Turns power on for the board
- * Configures board
- *
- */
-static u32 board_added(struct pci_func * func, struct controller * ctrl)
-{
- u8 hp_slot, slot;
- u8 slots_not_empty = 0;
- int index;
- u32 temp_register = 0xFFFFFFFF;
- u32 retval, rc = 0;
- struct pci_func *new_func = NULL;
- struct pci_func *t_func = NULL;
- struct slot *p_slot, *pslot;
- struct resource_lists res_lists;
- enum pci_bus_speed adapter_speed, bus_speed, max_bus_speed;
- u8 pi, mode;
-
- p_slot = shpchp_find_slot(ctrl, func->device);
- hp_slot = func->device - ctrl->slot_device_offset;
-
- dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n", __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot);
-
- /* Wait for exclusive access to hardware */
- down(&ctrl->crit_sect);
-
- /* Power on slot without connecting to bus */
- rc = p_slot->hpc_ops->power_on_slot(p_slot);
- if (rc) {
- err("%s: Failed to power on slot\n", __FUNCTION__);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return -1;
- }
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- rc = p_slot->hpc_ops->check_cmd_status(ctrl);
- if (rc) {
- err("%s: Failed to power on slot, error code(%d)\n", __FUNCTION__, rc);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return -1;
- }
-
- rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &adapter_speed);
- /* 0 = PCI 33Mhz, 1 = PCI 66 Mhz, 2 = PCI-X 66 PA, 4 = PCI-X 66 ECC, */
- /* 5 = PCI-X 133 PA, 7 = PCI-X 133 ECC, 0xa = PCI-X 133 Mhz 266, */
- /* 0xd = PCI-X 133 Mhz 533 */
- /* This encoding is different from the one used in cur_bus_speed & */
- /* max_bus_speed */
-
- if (rc || adapter_speed == PCI_SPEED_UNKNOWN) {
- err("%s: Can't get adapter speed or bus mode mismatch\n", __FUNCTION__);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return WRONG_BUS_FREQUENCY;
- }
-
- rc = p_slot->hpc_ops->get_cur_bus_speed(p_slot, &bus_speed);
- if (rc || bus_speed == PCI_SPEED_UNKNOWN) {
- err("%s: Can't get bus operation speed\n", __FUNCTION__);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return WRONG_BUS_FREQUENCY;
- }
-
- rc = p_slot->hpc_ops->get_max_bus_speed(p_slot, &max_bus_speed);
- if (rc || max_bus_speed == PCI_SPEED_UNKNOWN) {
- err("%s: Can't get max bus operation speed\n", __FUNCTION__);
- max_bus_speed = bus_speed;
- }
-
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
-
- rc = p_slot->hpc_ops->get_prog_int(p_slot, &pi);
- if (rc) {
- err("%s: Can't get controller programming interface, set it to 1\n", __FUNCTION__);
- pi = 1;
- }
- if (pi == 2) {
- for ( slot = 0; slot < ctrl->num_slots; slot++) {
- if (slot != hp_slot) {
- pslot = shpchp_find_slot(ctrl, slot + ctrl->slot_device_offset);
- t_func = shpchp_slot_find(pslot->bus, pslot->device, 0);
- slots_not_empty |= t_func->is_a_board;
- }
- }
-
- switch (adapter_speed) {
- case PCI_SPEED_133MHz_PCIX_533:
- case PCI_SPEED_133MHz_PCIX_266:
- if ((( bus_speed < 0xa ) || (bus_speed < 0xd)) && (max_bus_speed > bus_speed) &&
- ((max_bus_speed <= 0xa) || (max_bus_speed <= 0xd)) && (!slots_not_empty)) {
-
- /* Wait for exclusive access to hardware */
- down(&ctrl->crit_sect);
-
- rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, max_bus_speed);
- if (rc) {
- err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return WRONG_BUS_FREQUENCY;
- }
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- rc = p_slot->hpc_ops->check_cmd_status(ctrl);
- if (rc) {
- err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
- __FUNCTION__);
- err("%s: Error code (%d)\n", __FUNCTION__, rc);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return WRONG_BUS_FREQUENCY;
- }
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- }
- break;
- case PCI_SPEED_133MHz_PCIX_ECC:
- case PCI_SPEED_133MHz_PCIX:
-
- rc = p_slot->hpc_ops->get_mode1_ECC_cap(p_slot, &mode);
-
- if (rc) {
- err("%s: PI is 1 \n", __FUNCTION__);
- return WRONG_BUS_FREQUENCY;
- }
-
- if (mode) { /* Bus - Mode 1 ECC */
-
- if (bus_speed > 0x7) {
- err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
- return WRONG_BUS_FREQUENCY;
- }
-
- if ((bus_speed < 0x7) && (max_bus_speed <= 0x7) &&
- (bus_speed < max_bus_speed) && (!slots_not_empty)) {
-
- /* Wait for exclusive access to hardware */
- down(&ctrl->crit_sect);
-
- rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, max_bus_speed);
- if (rc) {
- err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return WRONG_BUS_FREQUENCY;
- }
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- rc = p_slot->hpc_ops->check_cmd_status(ctrl);
- if (rc) {
- err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
- __FUNCTION__);
- err("%s: Error code (%d)\n", __FUNCTION__, rc);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return WRONG_BUS_FREQUENCY;
- }
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- }
- } else {
- if (bus_speed > 0x4) {
- err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
- return WRONG_BUS_FREQUENCY;
- }
-
- if ((bus_speed < 0x4) && (max_bus_speed <= 0x4) &&
- (bus_speed < max_bus_speed) && (!slots_not_empty)) {
-
- /* Wait for exclusive access to hardware */
- down(&ctrl->crit_sect);
-
- rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, max_bus_speed);
- if (rc) {
- err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return WRONG_BUS_FREQUENCY;
- }
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- rc = p_slot->hpc_ops->check_cmd_status(ctrl);
- if (rc) {
- err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
- __FUNCTION__);
- err("%s: Error code (%d)\n", __FUNCTION__, rc);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return WRONG_BUS_FREQUENCY;
- }
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- }
- }
- break;
- case PCI_SPEED_66MHz_PCIX_ECC:
- case PCI_SPEED_66MHz_PCIX:
-
- rc = p_slot->hpc_ops->get_mode1_ECC_cap(p_slot, &mode);
-
- if (rc) {
- err("%s: PI is 1 \n", __FUNCTION__);
- return WRONG_BUS_FREQUENCY;
- }
-
- if (mode) { /* Bus - Mode 1 ECC */
-
- if (bus_speed > 0x5) {
- err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
- return WRONG_BUS_FREQUENCY;
- }
-
- if ((bus_speed < 0x5) && (max_bus_speed <= 0x5) &&
- (bus_speed < max_bus_speed) && (!slots_not_empty)) {
-
- /* Wait for exclusive access to hardware */
- down(&ctrl->crit_sect);
-
- rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, max_bus_speed);
- if (rc) {
- err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return WRONG_BUS_FREQUENCY;
- }
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- rc = p_slot->hpc_ops->check_cmd_status(ctrl);
- if (rc) {
- err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
- __FUNCTION__);
- err("%s: Error code (%d)\n", __FUNCTION__, rc);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return WRONG_BUS_FREQUENCY;
- }
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- }
- } else {
- if (bus_speed > 0x2) {
- err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
- return WRONG_BUS_FREQUENCY;
- }
-
- if ((bus_speed < 0x2) && (max_bus_speed <= 0x2) &&
- (bus_speed < max_bus_speed) && (!slots_not_empty)) {
-
- /* Wait for exclusive access to hardware */
- down(&ctrl->crit_sect);
-
- rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, max_bus_speed);
- if (rc) {
- err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return WRONG_BUS_FREQUENCY;
- }
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- rc = p_slot->hpc_ops->check_cmd_status(ctrl);
- if (rc) {
- err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
- __FUNCTION__);
- err("%s: Error code (%d)\n", __FUNCTION__, rc);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return WRONG_BUS_FREQUENCY;
- }
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- }
- }
- break;
- case PCI_SPEED_66MHz:
- if (bus_speed > 0x1) {
- err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
- return WRONG_BUS_FREQUENCY;
- }
- if (bus_speed == 0x1)
- ;
- if ((bus_speed == 0x0) && ( max_bus_speed == 0x1)) {
- /* Wait for exclusive access to hardware */
- down(&ctrl->crit_sect);
-
- rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, max_bus_speed);
- if (rc) {
- err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return WRONG_BUS_FREQUENCY;
- }
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- rc = p_slot->hpc_ops->check_cmd_status(ctrl);
- if (rc) {
- err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
- __FUNCTION__);
- err("%s: Error code (%d)\n", __FUNCTION__, rc);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return WRONG_BUS_FREQUENCY;
- }
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- }
- break;
- case PCI_SPEED_33MHz:
- if (bus_speed > 0x0) {
- err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
- return WRONG_BUS_FREQUENCY;
- }
- break;
- default:
- err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
- return WRONG_BUS_FREQUENCY;
- }
- } else {
- /* if adpater_speed == bus_speed, nothing to do here */
- if (adapter_speed != bus_speed) {
- for ( slot = 0; slot < ctrl->num_slots; slot++) {
- if (slot != hp_slot) {
- pslot = shpchp_find_slot(ctrl, slot + ctrl->slot_device_offset);
- t_func = shpchp_slot_find(pslot->bus, pslot->device, 0);
- slots_not_empty |= t_func->is_a_board;
- }
- }
-
- if (slots_not_empty != 0) { /* Other slots on the same bus are occupied */
- if ( adapter_speed < bus_speed ) {
- err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
- return WRONG_BUS_FREQUENCY;
- }
- /* Do nothing if adapter_speed >= bus_speed */
- }
- }
-
- if ((adapter_speed != bus_speed) && (slots_not_empty == 0)) {
- /* Other slots on the same bus are empty */
-
- rc = p_slot->hpc_ops->get_max_bus_speed(p_slot, &max_bus_speed);
- if (rc || max_bus_speed == PCI_SPEED_UNKNOWN) {
- err("%s: Can't get max bus operation speed\n", __FUNCTION__);
- max_bus_speed = bus_speed;
- }
-
- if (max_bus_speed == bus_speed) {
- /* if adapter_speed >= bus_speed, do nothing */
- if (adapter_speed < bus_speed) {
- /*
- * Try to lower bus speed to accommodate the adapter if other slots
- * on the same controller are empty
- */
-
- /* Wait for exclusive access to hardware */
- down(&ctrl->crit_sect);
-
- rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, adapter_speed);
- if (rc) {
- err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
- return WRONG_BUS_FREQUENCY;
- }
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- rc = p_slot->hpc_ops->check_cmd_status(ctrl);
- if (rc) {
- err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
- __FUNCTION__);
- err("%s: Error code (%d)\n", __FUNCTION__, rc);
- return WRONG_BUS_FREQUENCY;
- }
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
-
- }
- } else {
- /* Wait for exclusive access to hardware */
- down(&ctrl->crit_sect);
-
- /* max_bus_speed != bus_speed. Note: max_bus_speed should be > than bus_speed */
- if (adapter_speed < max_bus_speed)
- rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, adapter_speed);
- else
- rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, max_bus_speed);
-
- if (rc) {
- err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return WRONG_BUS_FREQUENCY;
- }
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- rc = p_slot->hpc_ops->check_cmd_status(ctrl);
- if (rc) {
- err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
- __FUNCTION__);
- err("%s: Error code (%d)\n", __FUNCTION__, rc);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return WRONG_BUS_FREQUENCY;
- }
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
-
- }
- }
- }
-
- /* Wait for exclusive access to hardware */
- down(&ctrl->crit_sect);
-
- /* turn on board, blink green LED, turn off Amber LED */
- rc = p_slot->hpc_ops->slot_enable(p_slot);
-
- if (rc) {
- err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return rc;
- }
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- rc = p_slot->hpc_ops->check_cmd_status(ctrl);
- if (rc) {
- err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return rc;
- }
-
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
-
- /* Wait for ~1 second */
- dbg("%s: before long_delay\n", __FUNCTION__);
- wait_for_ctrl_irq (ctrl);
- dbg("%s: afterlong_delay\n", __FUNCTION__);
-
- dbg("%s: func status = %x\n", __FUNCTION__, 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", __FUNCTION__, temp_register);
- rc = POWER_FAILURE;
- func->status = 0;
- } else {
- /* Get vendor/device ID u32 */
- rc = pci_bus_read_config_dword (ctrl->pci_dev->subordinate, PCI_DEVFN(func->device, func->function),
- PCI_VENDOR_ID, &temp_register);
- dbg("%s: pci_bus_read_config_dword returns %d\n", __FUNCTION__, rc);
- dbg("%s: temp_register is %x\n", __FUNCTION__, temp_register);
-
- if (rc != 0) {
- /* Something's wrong here */
- temp_register = 0xFFFFFFFF;
- dbg("%s: temp register set to %x by error\n", __FUNCTION__, 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) { /* Check for a board in the slot */
- 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, 0, 0);
- dbg("%s: back from configure_new_device\n", __FUNCTION__);
-
- 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;
-
- shpchp_resource_sort_and_combine(&(ctrl->mem_head));
- shpchp_resource_sort_and_combine(&(ctrl->p_mem_head));
- shpchp_resource_sort_and_combine(&(ctrl->io_head));
- shpchp_resource_sort_and_combine(&(ctrl->bus_head));
-
- if (rc) {
- /* Wait for exclusive access to hardware */
- down(&ctrl->crit_sect);
-
- /* turn off slot, turn on Amber LED, turn off Green LED */
- retval = p_slot->hpc_ops->slot_disable(p_slot);
- if (retval) {
- err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return retval;
- }
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- retval = p_slot->hpc_ops->check_cmd_status(ctrl);
- if (retval) {
- err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return retval;
- }
-
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
-
- return(rc);
- }
- shpchp_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)
- */
- index = 0;
- do {
- new_func = shpchp_slot_find(ctrl->slot_bus, func->device, index++);
- if (new_func && !new_func->pci_dev) {
- dbg("%s:call pci_hp_configure_dev\n", __FUNCTION__);
- shpchp_configure_device(ctrl, new_func);
- }
- } while (new_func);
-
- /* Wait for exclusive access to hardware */
- down(&ctrl->crit_sect);
-
- p_slot->hpc_ops->green_led_on(p_slot);
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
-
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
-
- } else {
- /* Wait for exclusive access to hardware */
- down(&ctrl->crit_sect);
-
- /* turn off slot, turn on Amber LED, turn off Green LED */
- rc = p_slot->hpc_ops->slot_disable(p_slot);
- if (rc) {
- err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return rc;
- }
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- rc = p_slot->hpc_ops->check_cmd_status(ctrl);
- if (rc) {
- err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return rc;
- }
-
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
-
- return(rc);
- }
- return 0;
-}
-
-
-/**
- * remove_board - Turns off slot and LED's
- *
- */
-static u32 remove_board(struct pci_func *func, struct controller *ctrl)
-{
- int index;
- u8 skip = 0;
- u8 device;
- u8 hp_slot;
- u32 rc;
- struct resource_lists res_lists;
- struct pci_func *temp_func;
- struct slot *p_slot;
-
- if (func == NULL)
- return(1);
-
- if (shpchp_unconfigure_device(func))
- return(1);
-
- device = func->device;
-
- hp_slot = func->device - ctrl->slot_device_offset;
- p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
-
- dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
-
- if ((ctrl->add_support) &&
- !(func->bus_head || func->mem_head || func->p_mem_head || func->io_head)) {
- /* Here we check to see if we've saved any of the board's
- * resources already. If so, we'll skip the attempt to
- * determine what's being used.
- */
- index = 0;
-
- temp_func = func;
-
- while ((temp_func = shpchp_slot_find(temp_func->bus, temp_func->device, index++))) {
- if (temp_func->bus_head || temp_func->mem_head
- || temp_func->p_mem_head || temp_func->io_head) {
- skip = 1;
- break;
- }
- }
-
- if (!skip)
- rc = shpchp_save_used_resources(ctrl, func, DISABLE_CARD);
- }
- /* Change status to shutdown */
- if (func->is_a_board)
- func->status = 0x01;
- func->configured = 0;
-
- /* Wait for exclusive access to hardware */
- down(&ctrl->crit_sect);
-
- /* turn off slot, turn on Amber LED, turn off Green LED */
- rc = p_slot->hpc_ops->slot_disable(p_slot);
- if (rc) {
- err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return rc;
- }
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- rc = p_slot->hpc_ops->check_cmd_status(ctrl);
- if (rc) {
- err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return rc;
- }
-
- rc = p_slot->hpc_ops->set_attention_status(p_slot, 0);
- if (rc) {
- err("%s: Issue of Set Attention command failed\n", __FUNCTION__);
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- return rc;
- }
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
-
- if (ctrl->add_support) {
- while (func) {
- 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;
-
- dbg("Returning resources to ctlr lists for (B/D/F) = (%#x/%#x/%#x)\n", func->bus,
- func->device, func->function);
-
- shpchp_return_board_resources(func, &res_lists);
-
- 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;
-
- shpchp_resource_sort_and_combine(&(ctrl->mem_head));
- shpchp_resource_sort_and_combine(&(ctrl->p_mem_head));
- shpchp_resource_sort_and_combine(&(ctrl->io_head));
- shpchp_resource_sort_and_combine(&(ctrl->bus_head));
-
- if (is_bridge(func)) {
- dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus,
- func->device, func->function);
- bridge_slot_remove(func);
- } else
- dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus,
- func->device, func->function);
- slot_remove(func);
-
- func = shpchp_slot_find(ctrl->slot_bus, device, 0);
- }
-
- /* Setup slot structure with entry for empty slot */
- func = shpchp_slot_create(ctrl->slot_bus);
-
- if (func == NULL) {
- return(1);
- }
-
- func->bus = ctrl->slot_bus;
- func->device = device;
- func->function = 0;
- func->configured = 0;
- func->switch_save = 0x10;
- func->is_a_board = 0;
- }
-
- return 0;
-}
-
-
-static void pushbutton_helper_thread (unsigned long data)
-{
- pushbutton_pending = data;
-
- up(&event_semaphore);
-}
-
-
-/* this is the main worker thread */
-static int event_thread(void* data)
-{
- struct controller *ctrl;
- lock_kernel();
- daemonize("shpchpd_event");
- unlock_kernel();
-
- while (1) {
- dbg("!!!!event_thread sleeping\n");
- down_interruptible (&event_semaphore);
- dbg("event_thread woken finished = %d\n", event_finished);
- if (event_finished || signal_pending(current))
- break;
- /* Do stuff here */
- if (pushbutton_pending)
- shpchp_pushbutton_thread(pushbutton_pending);
- else
- for (ctrl = shpchp_ctrl_list; ctrl; ctrl=ctrl->next)
- interrupt_event_handler(ctrl);
- }
- dbg("event_thread signals exit\n");
- up(&event_exit);
- return 0;
-}
-
-int shpchp_event_start_thread (void)
-{
- int pid;
-
- /* initialize our semaphores */
- init_MUTEX_LOCKED(&event_exit);
- event_finished=0;
-
- init_MUTEX_LOCKED(&event_semaphore);
- pid = kernel_thread(event_thread, 0, 0);
-
- if (pid < 0) {
- err ("Can't start up our event thread\n");
- return -1;
- }
- dbg("Our event thread pid = %d\n", pid);
- return 0;
-}
-
-
-void shpchp_event_stop_thread (void)
-{
- event_finished = 1;
- dbg("event_thread finish command given\n");
- up(&event_semaphore);
- dbg("wait for event_thread to exit\n");
- down(&event_exit);
-}
-
-
-static int update_slot_info (struct slot *slot)
-{
- struct hotplug_slot_info *info;
- int result;
-
- info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
-
- slot->hpc_ops->get_power_status(slot, &(info->power_status));
- slot->hpc_ops->get_attention_status(slot, &(info->attention_status));
- slot->hpc_ops->get_latch_status(slot, &(info->latch_status));
- slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status));
-
- result = pci_hp_change_slot_info(slot->hotplug_slot, info);
- kfree (info);
- return result;
-}
-
-static void interrupt_event_handler(struct controller *ctrl)
-{
- int loop = 0;
- int change = 1;
- struct pci_func *func;
- u8 hp_slot;
- u8 getstatus;
- struct slot *p_slot;
-
- dbg("%s:\n", __FUNCTION__);
- while (change) {
- change = 0;
-
- for (loop = 0; loop < 10; loop++) {
- if (ctrl->event_queue[loop].event_type != 0) {
- dbg("%s:loop %x event_type %x\n", __FUNCTION__, loop,
- ctrl->event_queue[loop].event_type);
- hp_slot = ctrl->event_queue[loop].hp_slot;
-
- func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
-
- p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
-
- dbg("%s: hp_slot %d, func %p, p_slot %p\n", __FUNCTION__, hp_slot, func, p_slot);
-
- if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) {
- dbg("%s: button cancel\n", __FUNCTION__);
- del_timer(&p_slot->task_event);
-
- switch (p_slot->state) {
- case BLINKINGOFF_STATE:
- /* Wait for exclusive access to hardware */
- down(&ctrl->crit_sect);
-
- p_slot->hpc_ops->green_led_on(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- p_slot->hpc_ops->set_attention_status(p_slot, 0);
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- break;
- case BLINKINGON_STATE:
- /* Wait for exclusive access to hardware */
- down(&ctrl->crit_sect);
-
- p_slot->hpc_ops->green_led_off(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- p_slot->hpc_ops->set_attention_status(p_slot, 0);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
-
- break;
- default:
- warn("Not a valid state\n");
- return;
- }
- info(msg_button_cancel, p_slot->number);
- p_slot->state = STATIC_STATE;
- } else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) {
- /* Button Pressed (No action on 1st press...) */
- dbg("%s: Button pressed\n", __FUNCTION__);
-
- p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
- if (getstatus) {
- /* slot is on */
- dbg("%s: slot is on\n", __FUNCTION__);
- p_slot->state = BLINKINGOFF_STATE;
- info(msg_button_off, p_slot->number);
- } else {
- /* slot is off */
- dbg("%s: slot is off\n", __FUNCTION__);
- p_slot->state = BLINKINGON_STATE;
- info(msg_button_on, p_slot->number);
- }
-
- /* Wait for exclusive access to hardware */
- down(&ctrl->crit_sect);
-
- /* blink green LED and turn off amber */
- p_slot->hpc_ops->green_led_blink(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- p_slot->hpc_ops->set_attention_status(p_slot, 0);
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
-
- init_timer(&p_slot->task_event);
- p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */
- p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
- p_slot->task_event.data = (unsigned long) p_slot;
-
- dbg("%s: add_timer p_slot = %p\n", __FUNCTION__,(void *) p_slot);
- add_timer(&p_slot->task_event);
- } else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
- /***********POWER FAULT********************/
- dbg("%s: power fault\n", __FUNCTION__);
- /* Wait for exclusive access to hardware */
- down(&ctrl->crit_sect);
-
- p_slot->hpc_ops->set_attention_status(p_slot, 1);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- p_slot->hpc_ops->green_led_off(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- /* Done with exclusive hardware access */
- up(&ctrl->crit_sect);
- } else {
- /* refresh notification */
- if (p_slot)
- update_slot_info(p_slot);
- }
-
- ctrl->event_queue[loop].event_type = 0;
-
- change = 1;
- }
- } /* End of FOR loop */
- }
-
- return;
-}
-
-
-/**
- * shpchp_pushbutton_thread
- *
- * Scheduled procedure to handle blocking stuff for the pushbuttons
- * Handles all pending events and exits.
- *
- */
-void shpchp_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 (shpchp_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 (shpchp_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 shpchp_enable_slot (struct slot *p_slot)
-{
- u8 getstatus = 0;
- int rc;
- struct pci_func *func;
-
- func = shpchp_slot_find(p_slot->bus, p_slot->device, 0);
- if (!func) {
- dbg("%s: Error! slot NULL\n", __FUNCTION__);
- return (1);
- }