static int __pciehp_link_set(struct controller *ctrl, bool enable) { u16 lnk_ctrl; int retval = 0; retval = pciehp_readw(ctrl, PCI_EXP_LNKCTL, &lnk_ctrl); if (retval) { ctrl_err(ctrl, "Cannot read LNKCTRL register\n"); return retval; } if (enable) lnk_ctrl &= ~PCI_EXP_LNKCTL_LD; else lnk_ctrl |= PCI_EXP_LNKCTL_LD; retval = pciehp_writew(ctrl, PCI_EXP_LNKCTL, lnk_ctrl); if (retval) { ctrl_err(ctrl, "Cannot write LNKCTRL register\n"); return retval; } ctrl_dbg(ctrl, "%s: lnk_ctrl = %x\n", __func__, lnk_ctrl); return retval; }
static int hpc_check_cmd_status(struct controller *ctrl) { int retval = 0; u16 cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F; switch (cmd_status >> 1) { case 0: retval = 0; break; case 1: retval = SWITCH_OPEN; ctrl_err(ctrl, "Switch opened!\n"); break; case 2: retval = INVALID_CMD; ctrl_err(ctrl, "Invalid HPC command!\n"); break; case 4: retval = INVALID_SPEED_MODE; ctrl_err(ctrl, "Invalid bus speed/mode!\n"); break; default: retval = cmd_status; } return retval; }
int pciehp_check_link_status(struct controller *ctrl) { u16 lnk_status; int retval = 0; /* * Data Link Layer Link Active Reporting must be capable for * hot-plug capable downstream port. But old controller might * not implement it. In this case, we wait for 1000 ms. */ if (ctrl->link_active_reporting) pcie_wait_link_active(ctrl); else msleep(1000); retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status); if (retval) { ctrl_err(ctrl, "Cannot read LNKSTATUS register\n"); return retval; } ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status); if ((lnk_status & PCI_EXP_LNKSTA_LT) || !(lnk_status & PCI_EXP_LNKSTA_NLW)) { ctrl_err(ctrl, "Link Training Error occurs \n"); retval = -1; return retval; } return retval; }
static void set_slot_off(struct controller *ctrl, struct slot * pslot) { /* turn off slot, turn on Amber LED, turn off Green LED if supported*/ if (POWER_CTRL(ctrl)) { if (pslot->hpc_ops->power_off_slot(pslot)) { ctrl_err(ctrl, "Issue of Slot Power Off command failed\n"); return; } } /* * After turning power off, we must wait for at least 1 second * before taking any action that relies on power having been * removed from the slot/adapter. */ msleep(1000); if (PWR_LED(ctrl)) pslot->hpc_ops->green_led_off(pslot); if (ATTN_LED(ctrl)) { if (pslot->hpc_ops->set_attention_status(pslot, 1)) { ctrl_err(ctrl, "Issue of Set Attention Led command failed\n"); return; } } }
/** * board_added - Called after a board has been added to the system. * @p_slot: &slot where board is added * * Turns power on for the board. * Configures board. */ static int board_added(struct slot *p_slot) { int retval = 0; struct controller *ctrl = p_slot->ctrl; struct pci_bus *parent = ctrl->pci_dev->subordinate; ctrl_dbg(ctrl, "%s: slot device, slot offset, hp slot = %d, %d, %d\n", __func__, p_slot->device, ctrl->slot_device_offset, p_slot->hp_slot); if (POWER_CTRL(ctrl)) { /* Power on slot */ retval = p_slot->hpc_ops->power_on_slot(p_slot); if (retval) return retval; } if (PWR_LED(ctrl)) p_slot->hpc_ops->green_led_blink(p_slot); /* Check link training status */ retval = p_slot->hpc_ops->check_lnk_status(ctrl); if (retval) { ctrl_err(ctrl, "Failed to check link status\n"); set_slot_off(ctrl, p_slot); return retval; } /* Check for a power fault */ if (p_slot->hpc_ops->query_power_fault(p_slot)) { ctrl_dbg(ctrl, "Power fault detected\n"); retval = POWER_FAILURE; goto err_exit; } retval = pciehp_configure_device(p_slot); if (retval) { ctrl_err(ctrl, "Cannot add device at %04x:%02x:%02x\n", pci_domain_nr(parent), p_slot->bus, p_slot->device); goto err_exit; } /* * Some PCI Express root ports require fixup after hot-plug operation. */ if (pcie_mch_quirk) pci_fixup_device(pci_fixup_final, ctrl->pci_dev); if (PWR_LED(ctrl)) p_slot->hpc_ops->green_led_on(p_slot); return 0; err_exit: set_slot_off(ctrl, p_slot); return retval; }
/** * board_added - Called after a board has been added to the system. * @p_slot: &slot where board is added * * Turns power on for the board. * Configures board. */ static int board_added(struct slot *p_slot) { int retval = 0; struct controller *ctrl = p_slot->ctrl; struct pci_bus *parent = ctrl->pcie->port->subordinate; if (POWER_CTRL(ctrl)) { /* Power on slot */ retval = pciehp_power_on_slot(p_slot); if (retval) return retval; } pciehp_green_led_blink(p_slot); /* Check link training status */ pm_runtime_get_sync(&ctrl->pcie->port->dev); retval = pciehp_check_link_status(ctrl); if (retval) { ctrl_err(ctrl, "Failed to check link status\n"); goto err_exit; } /* Check for a power fault */ if (ctrl->power_fault_detected || pciehp_query_power_fault(p_slot)) { ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(p_slot)); retval = -EIO; goto err_exit; } retval = pciehp_configure_device(p_slot); if (retval) { ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n", pci_domain_nr(parent), parent->number); if (retval != -EEXIST) goto err_exit; } pm_runtime_put(&ctrl->pcie->port->dev); pciehp_green_led_on(p_slot); pciehp_set_attention_status(p_slot, 0); return 0; err_exit: pm_runtime_put(&ctrl->pcie->port->dev); set_slot_off(ctrl, p_slot); return retval; }
int pciehp_power_on_slot(struct slot * slot) { struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 cmd_mask; u16 slot_status; u16 lnk_status; int retval = 0; /* Clear sticky power-fault bit from previous power failures */ retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); if (retval) { ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS register\n", __func__); return retval; } slot_status &= PCI_EXP_SLTSTA_PFD; if (slot_status) { retval = pciehp_writew(ctrl, PCI_EXP_SLTSTA, slot_status); if (retval) { ctrl_err(ctrl, "%s: Cannot write to SLOTSTATUS register\n", __func__); return retval; } } ctrl->power_fault_detected = 0; slot_cmd = POWER_ON; cmd_mask = PCI_EXP_SLTCTL_PCC; retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); if (retval) { ctrl_err(ctrl, "Write %x command failed!\n", slot_cmd); return retval; } ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status); if (retval) { ctrl_err(ctrl, "%s: Cannot read LNKSTA register\n", __func__); return retval; } pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status); return retval; }
int pciehp_get_cur_link_speed(struct slot *slot, enum pci_bus_speed *value) { struct controller *ctrl = slot->ctrl; enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN; int retval = 0; u16 lnk_status; retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status); if (retval) { ctrl_err(ctrl, "%s: Cannot read LNKSTATUS register\n", __func__); return retval; } switch (lnk_status & PCI_EXP_LNKSTA_CLS) { case 1: lnk_speed = PCIE_2_5GB; break; case 2: lnk_speed = PCIE_5_0GB; break; default: lnk_speed = PCIE_LNK_SPEED_UNKNOWN; break; } *value = lnk_speed; ctrl_dbg(ctrl, "Current link speed = %d\n", lnk_speed); return retval; }
int pciehp_get_max_link_speed(struct slot *slot, enum pci_bus_speed *value) { struct controller *ctrl = slot->ctrl; enum pcie_link_speed lnk_speed; u32 lnk_cap; int retval = 0; retval = pciehp_readl(ctrl, PCI_EXP_LNKCAP, &lnk_cap); if (retval) { ctrl_err(ctrl, "%s: Cannot read LNKCAP register\n", __func__); return retval; } switch (lnk_cap & 0x000F) { case 1: lnk_speed = PCIE_2_5GB; break; case 2: lnk_speed = PCIE_5_0GB; break; default: lnk_speed = PCIE_LNK_SPEED_UNKNOWN; break; } *value = lnk_speed; ctrl_dbg(ctrl, "Max link speed = %d\n", lnk_speed); return retval; }
int pciehp_power_on_slot(struct slot *slot) { struct controller *ctrl = slot->ctrl; struct pci_dev *pdev = ctrl_dev(ctrl); u16 slot_status; int retval; /* Clear sticky power-fault bit from previous power failures */ pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); if (slot_status & PCI_EXP_SLTSTA_PFD) pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_PFD); ctrl->power_fault_detected = 0; pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_ON, PCI_EXP_SLTCTL_PCC); ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, PCI_EXP_SLTCTL_PWR_ON); retval = pciehp_link_enable(ctrl); if (retval) ctrl_err(ctrl, "%s: Can not enable the link!\n", __func__); return retval; }
int pciehp_power_off_slot(struct slot * slot) { struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 cmd_mask; int retval; /* Disable the link at first */ pciehp_link_disable(ctrl); /* wait the link is down */ if (ctrl->link_active_reporting) pcie_wait_link_not_active(ctrl); else msleep(1000); slot_cmd = POWER_OFF; cmd_mask = PCI_EXP_SLTCTL_PCC; retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); if (retval) { ctrl_err(ctrl, "Write command failed!\n"); return retval; } ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); return 0; }
int shpchp_unconfigure_device(struct slot *p_slot) { int rc = 0; int j; u8 bctl = 0; struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; struct controller *ctrl = p_slot->ctrl; ctrl_dbg(ctrl, "%s: domain:bus:dev = %04x:%02x:%02x\n", __func__, pci_domain_nr(parent), p_slot->bus, p_slot->device); for (j = 0; j < 8 ; j++) { struct pci_dev *temp = pci_get_slot(parent, (p_slot->device << 3) | j); if (!temp) continue; if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) { pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl); if (bctl & PCI_BRIDGE_CTL_VGA) { ctrl_err(ctrl, "Cannot remove display device %s\n", pci_name(temp)); pci_dev_put(temp); rc = -EINVAL; break; } } pci_remove_bus_device(temp); pci_dev_put(temp); } return rc; }
int pcie_enable_notification(struct controller *ctrl) { u16 cmd, mask; /* * TBD: Power fault detected software notification support. * * Power fault detected software notification is not enabled * now, because it caused power fault detected interrupt storm * on some machines. On those machines, power fault detected * bit in the slot status register was set again immediately * when it is cleared in the interrupt service routine, and * next power fault detected interrupt was notified again. */ cmd = PCI_EXP_SLTCTL_PDCE; if (ATTN_BUTTN(ctrl)) cmd |= PCI_EXP_SLTCTL_ABPE; if (MRL_SENS(ctrl)) cmd |= PCI_EXP_SLTCTL_MRLSCE; if (!pciehp_poll_mode) cmd |= PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE; mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE | PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE); if (pcie_write_cmd(ctrl, cmd, mask)) { ctrl_err(ctrl, "Cannot enable software notification\n"); return -1; } return 0; }
int pciehp_get_power_status(struct slot *slot, u8 *status) { struct controller *ctrl = slot->ctrl; u16 slot_ctrl; u8 pwr_state; int retval = 0; retval = pciehp_readw(ctrl, PCI_EXP_SLTCTL, &slot_ctrl); if (retval) { ctrl_err(ctrl, "%s: Cannot read SLOTCTRL register\n", __func__); return retval; } ctrl_dbg(ctrl, "%s: SLOTCTRL %x value read %x\n", __func__, pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_ctrl); pwr_state = (slot_ctrl & PCI_EXP_SLTCTL_PCC) >> 10; switch (pwr_state) { case 0: *status = 1; break; case 1: *status = 0; break; default: *status = 0xFF; break; } return retval; }
/** * remove_board - Turns off slot and LEDs * @p_slot: slot where board is being removed */ static int remove_board(struct slot *p_slot) { int retval = 0; struct controller *ctrl = p_slot->ctrl; retval = pciehp_unconfigure_device(p_slot); if (retval) return retval; ctrl_dbg(ctrl, "%s: hp_slot = %d\n", __func__, p_slot->hp_slot); if (POWER_CTRL(ctrl)) { /* power off slot */ retval = p_slot->hpc_ops->power_off_slot(p_slot); if (retval) { ctrl_err(ctrl, "Issue of Slot Disable command failed\n"); return retval; } } /* * After turning power off, we must wait for at least 1 second * before taking any action that relies on power having been * removed from the slot/adapter. */ msleep(1000); if (PWR_LED(ctrl)) /* turn off Green LED */ p_slot->hpc_ops->green_led_off(p_slot); return 0; }
static int fix_bus_speed(struct controller *ctrl, struct slot *pslot, u8 flag, enum pci_bus_speed asp, enum pci_bus_speed bsp, enum pci_bus_speed msp) { int rc = 0; /* * If other slots on the same bus are occupied, we cannot * change the bus speed. */ if (flag) { if (asp < bsp) { ctrl_err(ctrl, "Speed of bus %x and adapter %x " "mismatch\n", bsp, asp); rc = WRONG_BUS_FREQUENCY; } return rc; } if (asp < msp) { if (bsp != asp) rc = change_bus_speed(ctrl, pslot, asp); } else { if (bsp != msp) rc = change_bus_speed(ctrl, pslot, msp); } return rc; }
static int hpc_power_on_slot(struct slot * slot) { struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 cmd_mask; u16 slot_status; int retval = 0; ctrl_dbg(ctrl, "%s: slot->hp_slot %x\n", __func__, slot->hp_slot); /* Clear sticky power-fault bit from previous power failures */ retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); if (retval) { ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS register\n", __func__); return retval; } slot_status &= PCI_EXP_SLTSTA_PFD; if (slot_status) { retval = pciehp_writew(ctrl, PCI_EXP_SLTSTA, slot_status); if (retval) { ctrl_err(ctrl, "%s: Cannot write to SLOTSTATUS register\n", __func__); return retval; } } slot_cmd = POWER_ON; cmd_mask = PCI_EXP_SLTCTL_PCC; if (!pciehp_poll_mode) { /* Enable power fault detection turned off at power off time */ slot_cmd |= PCI_EXP_SLTCTL_PFDE; cmd_mask |= PCI_EXP_SLTCTL_PFDE; } retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); if (retval) { ctrl_err(ctrl, "Write %x command failed!\n", slot_cmd); return retval; } ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); ctrl->power_fault_detected = 0; return retval; }
static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) { struct controller *ctrl = slot->ctrl; u16 cmd_status; int retval = 0; u16 temp_word; mutex_lock(&slot->ctrl->cmd_lock); if (!shpc_poll_ctrl_busy(ctrl)) { /* After 1 sec and and the controller is still busy */ ctrl_err(ctrl, "Controller is still busy after 1 sec\n"); retval = -EBUSY; goto out; } ++t_slot; temp_word = (t_slot << 8) | (cmd & 0xFF); ctrl_dbg(ctrl, "%s: t_slot %x cmd %x\n", __func__, t_slot, cmd); /* To make sure the Controller Busy bit is 0 before we send out the * command. */ shpc_writew(ctrl, CMD, temp_word); /* * Wait for command completion. */ retval = shpc_wait_cmd(slot->ctrl); if (retval) goto out; cmd_status = hpc_check_cmd_status(slot->ctrl); if (cmd_status) { ctrl_err(ctrl, "Failed to issued command 0x%x (error code = %d)\n", cmd, cmd_status); retval = -EIO; } out: mutex_unlock(&slot->ctrl->cmd_lock); return retval; }
int pciehp_check_link_status(struct controller *ctrl) { u16 lnk_status; int retval = 0; bool found = false; /* * Data Link Layer Link Active Reporting must be capable for * hot-plug capable downstream port. But old controller might * not implement it. In this case, we wait for 1000 ms. */ if (ctrl->link_active_reporting) pcie_wait_link_active(ctrl); else msleep(1000); /* wait 100ms before read pci conf, and try in 1s */ msleep(100); found = pci_bus_check_dev(ctrl->pcie->port->subordinate, PCI_DEVFN(0, 0)); retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status); if (retval) { ctrl_err(ctrl, "Cannot read LNKSTATUS register\n"); return retval; } ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status); if ((lnk_status & PCI_EXP_LNKSTA_LT) || !(lnk_status & PCI_EXP_LNKSTA_NLW)) { ctrl_err(ctrl, "Link Training Error occurs \n"); retval = -1; return retval; } pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status); if (!found && !retval) retval = -1; return retval; }
/* The following routines constitute the bulk of the hotplug controller logic */ static int change_bus_speed(struct controller *ctrl, struct slot *p_slot, enum pci_bus_speed speed) { int rc = 0; ctrl_dbg(ctrl, "Change speed to %d\n", speed); if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, speed))) { ctrl_err(ctrl, "%s: Issue of set bus speed mode command " "failed\n", __func__); return WRONG_BUS_FREQUENCY; } return rc; }
int pciehp_query_power_fault(struct slot *slot) { struct controller *ctrl = slot->ctrl; u16 slot_status; int retval; retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); if (retval) { ctrl_err(ctrl, "Cannot check for power fault\n"); return retval; } return !!(slot_status & PCI_EXP_SLTSTA_PFD); }
int pciehp_check_link_status(struct controller *ctrl) { u16 lnk_status; int retval = 0; /* * Data Link Layer Link Active Reporting must be capable for * hot-plug capable downstream port. But old controller might * not implement it. In this case, we wait for 1000 ms. */ if (ctrl->link_active_reporting){ /* Wait for Data Link Layer Link Active bit to be set */ pcie_wait_link_active(ctrl); /* * We must wait for 100 ms after the Data Link Layer * Link Active bit reads 1b before initiating a * configuration access to the hot added device. */ msleep(100); } else msleep(1000); retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status); if (retval) { ctrl_err(ctrl, "Cannot read LNKSTATUS register\n"); return retval; } ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status); if ((lnk_status & PCI_EXP_LNKSTA_LT) || !(lnk_status & PCI_EXP_LNKSTA_NLW)) { ctrl_err(ctrl, "Link Training Error occurs \n"); retval = -1; return retval; } return retval; }
u8 pciehp_handle_power_fault(struct slot *p_slot) { u32 event_type; struct controller *ctrl = p_slot->ctrl; /* power fault */ ctrl_dbg(ctrl, "Power fault interrupt received\n"); ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(p_slot)); event_type = INT_POWER_FAULT; ctrl_info(ctrl, "Power fault bit %x set\n", 0); queue_interrupt_event(p_slot, event_type); return 1; }
int pciehp_get_cur_lnk_width(struct slot *slot, enum pcie_link_width *value) { struct controller *ctrl = slot->ctrl; enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN; int retval = 0; u16 lnk_status; retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status); if (retval) { ctrl_err(ctrl, "%s: Cannot read LNKSTATUS register\n", __func__); return retval; } switch ((lnk_status & PCI_EXP_LNKSTA_NLW) >> 4){ case 0: lnk_wdth = PCIE_LNK_WIDTH_RESRV; break; case 1: lnk_wdth = PCIE_LNK_X1; break; case 2: lnk_wdth = PCIE_LNK_X2; break; case 4: lnk_wdth = PCIE_LNK_X4; break; case 8: lnk_wdth = PCIE_LNK_X8; break; case 12: lnk_wdth = PCIE_LNK_X12; break; case 16: lnk_wdth = PCIE_LNK_X16; break; case 32: lnk_wdth = PCIE_LNK_X32; break; default: lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN; break; } *value = lnk_wdth; ctrl_dbg(ctrl, "Current link width = %d\n", lnk_wdth); return retval; }
static int hpc_get_emi_status(struct slot *slot, u8 *status) { struct controller *ctrl = slot->ctrl; u16 slot_status; int retval; retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); if (retval) { ctrl_err(ctrl, "Cannot check EMI status\n"); return retval; } *status = !!(slot_status & PCI_EXP_SLTSTA_EIS); return retval; }
/** * remove_board - Turns off slot and LEDs * @p_slot: target &slot */ static int remove_board(struct slot *p_slot) { struct controller *ctrl = p_slot->ctrl; u8 hp_slot; int rc; if (shpchp_unconfigure_device(p_slot)) return(1); hp_slot = p_slot->device - ctrl->slot_device_offset; p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); ctrl_dbg(ctrl, "%s: hp_slot = %d\n", __func__, hp_slot); /* Change status to shutdown */ if (p_slot->is_a_board) p_slot->status = 0x01; /* turn off slot, turn on Amber LED, turn off Green LED */ rc = p_slot->hpc_ops->slot_disable(p_slot); if (rc) { ctrl_err(ctrl, "%s: Issue of Slot Disable command failed\n", __func__); return rc; } rc = p_slot->hpc_ops->set_attention_status(p_slot, 0); if (rc) { ctrl_err(ctrl, "Issue of Set Attention command failed\n"); return rc; } p_slot->pwr_save = 0; p_slot->is_a_board = 0; return 0; }
static int hpc_get_max_lnk_width(struct slot *slot, enum pcie_link_width *value) { struct controller *ctrl = slot->ctrl; enum pcie_link_width lnk_wdth; u32 lnk_cap; int retval = 0; retval = pciehp_readl(ctrl, PCI_EXP_LNKCAP, &lnk_cap); if (retval) { ctrl_err(ctrl, "%s: Cannot read LNKCAP register\n", __func__); return retval; } switch ((lnk_cap & PCI_EXP_LNKSTA_NLW) >> 4){ case 0: lnk_wdth = PCIE_LNK_WIDTH_RESRV; break; case 1: lnk_wdth = PCIE_LNK_X1; break; case 2: lnk_wdth = PCIE_LNK_X2; break; case 4: lnk_wdth = PCIE_LNK_X4; break; case 8: lnk_wdth = PCIE_LNK_X8; break; case 12: lnk_wdth = PCIE_LNK_X12; break; case 16: lnk_wdth = PCIE_LNK_X16; break; case 32: lnk_wdth = PCIE_LNK_X32; break; default: lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN; break; } *value = lnk_wdth; ctrl_dbg(ctrl, "Max link width = %d\n", lnk_wdth); return retval; }
void pciehp_queue_interrupt_event(struct slot *p_slot, u32 event_type) { struct event_info *info; info = kmalloc(sizeof(*info), GFP_ATOMIC); if (!info) { ctrl_err(p_slot->ctrl, "dropped event %d (ENOMEM)\n", event_type); return; } INIT_WORK(&info->work, interrupt_event_handler); info->event_type = event_type; info->p_slot = p_slot; queue_work(p_slot->wq, &info->work); }
int pciehp_get_adapter_status(struct slot *slot, u8 *status) { struct controller *ctrl = slot->ctrl; u16 slot_status; int retval; retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); if (retval) { ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS register\n", __func__); return retval; } *status = !!(slot_status & PCI_EXP_SLTSTA_PDS); return 0; }
int pciehp_power_off_slot(struct slot * slot) { struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 cmd_mask; int retval; slot_cmd = POWER_OFF; cmd_mask = PCI_EXP_SLTCTL_PCC; retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); if (retval) { ctrl_err(ctrl, "Write command failed!\n"); return retval; } ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); return 0; }