📄 shpchp_hpc.c
字号:
shpc_write_cmd(slot, slot->hp_slot, SET_PWR_ON);}static void hpc_set_green_led_off(struct slot *slot){ shpc_write_cmd(slot, slot->hp_slot, SET_PWR_OFF);}static void hpc_set_green_led_blink(struct slot *slot){ shpc_write_cmd(slot, slot->hp_slot, SET_PWR_BLINK);}static void hpc_release_ctlr(struct controller *ctrl){ int i; u32 slot_reg, serr_int; /* * Mask event interrupts and SERRs of all slots */ for (i = 0; i < ctrl->num_slots; i++) { slot_reg = shpc_readl(ctrl, SLOT_REG(i)); slot_reg |= (PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK | BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK | CON_PFAULT_INTR_MASK | MRL_CHANGE_SERR_MASK | CON_PFAULT_SERR_MASK); slot_reg &= ~SLOT_REG_RSVDZ_MASK; shpc_writel(ctrl, SLOT_REG(i), slot_reg); } cleanup_slots(ctrl); /* * Mask SERR and System Interrupt generation */ serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); serr_int |= (GLOBAL_INTR_MASK | GLOBAL_SERR_MASK | COMMAND_INTR_MASK | ARBITER_SERR_MASK); serr_int &= ~SERR_INTR_RSVDZ_MASK; shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); if (shpchp_poll_mode) del_timer(&ctrl->poll_timer); else { free_irq(ctrl->pci_dev->irq, ctrl); pci_disable_msi(ctrl->pci_dev); } iounmap(ctrl->creg); release_mem_region(ctrl->mmio_base, ctrl->mmio_size); /* * If this is the last controller to be released, destroy the * shpchpd work queue */ if (atomic_dec_and_test(&shpchp_num_controllers)) destroy_workqueue(shpchp_wq);}static int hpc_power_on_slot(struct slot * slot){ int retval; retval = shpc_write_cmd(slot, slot->hp_slot, SET_SLOT_PWR); if (retval) err("%s: Write command failed!\n", __func__); return retval;}static int hpc_slot_enable(struct slot * slot){ int retval; /* Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */ retval = shpc_write_cmd(slot, slot->hp_slot, SET_SLOT_ENABLE | SET_PWR_BLINK | SET_ATTN_OFF); if (retval) err("%s: Write command failed!\n", __func__); return retval;}static int hpc_slot_disable(struct slot * slot){ int retval; /* Slot - Disable, Power Indicator - Off, Attention Indicator - On */ retval = shpc_write_cmd(slot, slot->hp_slot, SET_SLOT_DISABLE | SET_PWR_OFF | SET_ATTN_ON); if (retval) err("%s: Write command failed!\n", __func__); return retval;}static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value){ int retval; struct controller *ctrl = slot->ctrl; u8 pi, cmd; pi = shpc_readb(ctrl, PROG_INTERFACE); if ((pi == 1) && (value > PCI_SPEED_133MHz_PCIX)) return -EINVAL; switch (value) { case PCI_SPEED_33MHz: cmd = SETA_PCI_33MHZ; break; case PCI_SPEED_66MHz: cmd = SETA_PCI_66MHZ; break; case PCI_SPEED_66MHz_PCIX: cmd = SETA_PCIX_66MHZ; break; case PCI_SPEED_100MHz_PCIX: cmd = SETA_PCIX_100MHZ; break; case PCI_SPEED_133MHz_PCIX: cmd = SETA_PCIX_133MHZ; break; case PCI_SPEED_66MHz_PCIX_ECC: cmd = SETB_PCIX_66MHZ_EM; break; case PCI_SPEED_100MHz_PCIX_ECC: cmd = SETB_PCIX_100MHZ_EM; break; case PCI_SPEED_133MHz_PCIX_ECC: cmd = SETB_PCIX_133MHZ_EM; break; case PCI_SPEED_66MHz_PCIX_266: cmd = SETB_PCIX_66MHZ_266; break; case PCI_SPEED_100MHz_PCIX_266: cmd = SETB_PCIX_100MHZ_266; break; case PCI_SPEED_133MHz_PCIX_266: cmd = SETB_PCIX_133MHZ_266; break; case PCI_SPEED_66MHz_PCIX_533: cmd = SETB_PCIX_66MHZ_533; break; case PCI_SPEED_100MHz_PCIX_533: cmd = SETB_PCIX_100MHZ_533; break; case PCI_SPEED_133MHz_PCIX_533: cmd = SETB_PCIX_133MHZ_533; break; default: return -EINVAL; } retval = shpc_write_cmd(slot, 0, cmd); if (retval) err("%s: Write command failed!\n", __func__); return retval;}static irqreturn_t shpc_isr(int irq, void *dev_id){ struct controller *ctrl = (struct controller *)dev_id; u32 serr_int, slot_reg, intr_loc, intr_loc2; int hp_slot; /* Check to see if it was our interrupt */ intr_loc = shpc_readl(ctrl, INTR_LOC); if (!intr_loc) return IRQ_NONE; dbg("%s: intr_loc = %x\n",__func__, intr_loc); if(!shpchp_poll_mode) { /* * Mask Global Interrupt Mask - see implementation * note on p. 139 of SHPC spec rev 1.0 */ serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); serr_int |= GLOBAL_INTR_MASK; serr_int &= ~SERR_INTR_RSVDZ_MASK; shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); intr_loc2 = shpc_readl(ctrl, INTR_LOC); dbg("%s: intr_loc2 = %x\n",__func__, intr_loc2); } if (intr_loc & CMD_INTR_PENDING) { /* * Command Complete Interrupt Pending * RO only - clear by writing 1 to the Command Completion * Detect bit in Controller SERR-INT register */ serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); serr_int &= ~SERR_INTR_RSVDZ_MASK; shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); wake_up_interruptible(&ctrl->queue); } if (!(intr_loc & ~CMD_INTR_PENDING)) goto out; for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { /* To find out which slot has interrupt pending */ if (!(intr_loc & SLOT_INTR_PENDING(hp_slot))) continue; slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); dbg("%s: Slot %x with intr, slot register = %x\n", __func__, hp_slot, slot_reg); if (slot_reg & MRL_CHANGE_DETECTED) shpchp_handle_switch_change(hp_slot, ctrl); if (slot_reg & BUTTON_PRESS_DETECTED) shpchp_handle_attention_button(hp_slot, ctrl); if (slot_reg & PRSNT_CHANGE_DETECTED) shpchp_handle_presence_change(hp_slot, ctrl); if (slot_reg & (ISO_PFAULT_DETECTED | CON_PFAULT_DETECTED)) shpchp_handle_power_fault(hp_slot, ctrl); /* Clear all slot events */ slot_reg &= ~SLOT_REG_RSVDZ_MASK; shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg); } out: if (!shpchp_poll_mode) { /* Unmask Global Interrupt Mask */ serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE); serr_int &= ~(GLOBAL_INTR_MASK | SERR_INTR_RSVDZ_MASK); shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); } return IRQ_HANDLED;}static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value){ int retval = 0; struct controller *ctrl = slot->ctrl; enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; u8 pi = shpc_readb(ctrl, PROG_INTERFACE); u32 slot_avail1 = shpc_readl(ctrl, SLOT_AVAIL1); u32 slot_avail2 = shpc_readl(ctrl, SLOT_AVAIL2); if (pi == 2) { if (slot_avail2 & SLOT_133MHZ_PCIX_533) bus_speed = PCI_SPEED_133MHz_PCIX_533; else if (slot_avail2 & SLOT_100MHZ_PCIX_533) bus_speed = PCI_SPEED_100MHz_PCIX_533; else if (slot_avail2 & SLOT_66MHZ_PCIX_533) bus_speed = PCI_SPEED_66MHz_PCIX_533; else if (slot_avail2 & SLOT_133MHZ_PCIX_266) bus_speed = PCI_SPEED_133MHz_PCIX_266; else if (slot_avail2 & SLOT_100MHZ_PCIX_266) bus_speed = PCI_SPEED_100MHz_PCIX_266; else if (slot_avail2 & SLOT_66MHZ_PCIX_266) bus_speed = PCI_SPEED_66MHz_PCIX_266; } if (bus_speed == PCI_SPEED_UNKNOWN) { if (slot_avail1 & SLOT_133MHZ_PCIX) bus_speed = PCI_SPEED_133MHz_PCIX; else if (slot_avail1 & SLOT_100MHZ_PCIX) bus_speed = PCI_SPEED_100MHz_PCIX; else if (slot_avail1 & SLOT_66MHZ_PCIX) bus_speed = PCI_SPEED_66MHz_PCIX; else if (slot_avail2 & SLOT_66MHZ) bus_speed = PCI_SPEED_66MHz; else if (slot_avail1 & SLOT_33MHZ) bus_speed = PCI_SPEED_33MHz; else retval = -ENODEV; } *value = bus_speed; dbg("Max bus speed = %d\n", bus_speed); return retval;}static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value){ int retval = 0; struct controller *ctrl = slot->ctrl; enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; u16 sec_bus_reg = shpc_readw(ctrl, SEC_BUS_CONFIG); u8 pi = shpc_readb(ctrl, PROG_INTERFACE); u8 speed_mode = (pi == 2) ? (sec_bus_reg & 0xF) : (sec_bus_reg & 0x7); if ((pi == 1) && (speed_mode > 4)) { *value = PCI_SPEED_UNKNOWN; return -ENODEV; } switch (speed_mode) { case 0x0: *value = PCI_SPEED_33MHz; break; case 0x1: *value = PCI_SPEED_66MHz; break; case 0x2: *value = PCI_SPEED_66MHz_PCIX; break; case 0x3: *value = PCI_SPEED_100MHz_PCIX; break; case 0x4: *value = PCI_SPEED_133MHz_PCIX; break; case 0x5: *value = PCI_SPEED_66MHz_PCIX_ECC; break; case 0x6: *value = PCI_SPEED_100MHz_PCIX_ECC; break; case 0x7: *value = PCI_SPEED_133MHz_PCIX_ECC; break; case 0x8: *value = PCI_SPEED_66MHz_PCIX_266; break; case 0x9: *value = PCI_SPEED_100MHz_PCIX_266; break; case 0xa: *value = PCI_SPEED_133MHz_PCIX_266; break; case 0xb: *value = PCI_SPEED_66MHz_PCIX_533; break; case 0xc: *value = PCI_SPEED_100MHz_PCIX_533; break; case 0xd: *value = PCI_SPEED_133MHz_PCIX_533; break; default: *value = PCI_SPEED_UNKNOWN; retval = -ENODEV; break; } dbg("Current bus speed = %d\n", bus_speed); return retval;}static struct hpc_ops shpchp_hpc_ops = { .power_on_slot = hpc_power_on_slot, .slot_enable = hpc_slot_enable, .slot_disable = hpc_slot_disable, .set_bus_speed_mode = hpc_set_bus_speed_mode, .set_attention_status = hpc_set_attention_status, .get_power_status = hpc_get_power_status, .get_attention_status = hpc_get_attention_status, .get_latch_status = hpc_get_latch_status, .get_adapter_status = hpc_get_adapter_status, .get_max_bus_speed = hpc_get_max_bus_speed, .get_cur_bus_speed = hpc_get_cur_bus_speed, .get_adapter_speed = hpc_get_adapter_speed, .get_mode1_ECC_cap = hpc_get_mode1_ECC_cap, .get_prog_int = hpc_get_prog_int, .query_power_fault = hpc_query_power_fault, .green_led_on = hpc_set_green_led_on, .green_led_off = hpc_set_green_led_off, .green_led_blink = hpc_set_green_led_blink, .release_ctlr = hpc_release_ctlr,};int shpc_init(struct controller *ctrl, struct pci_dev *pdev){ int rc = -1, num_slots = 0; u8 hp_slot; u32 shpc_base_offset; u32 tempdword, slot_reg, slot_config; u8 i; ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */ if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device == PCI_DEVICE_ID_AMD_GOLAM_7450)) { /* amd shpc driver doesn't use Base Offset; assume 0 */ ctrl->mmio_base = pci_resource_start(pdev, 0); ctrl->mmio_size = pci_resource_len(pdev, 0); } else { ctrl->cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC); if (!ctrl->cap_offset) { err("%s : cap_offset == 0\n", __func__); goto abort; } dbg("%s: cap_offset = %x\n", __func__, ctrl->cap_offset); rc = shpc_indirect_read(ctrl, 0, &shpc_base_offset); if (rc) { err("%s: cannot read base_offset\n", __func__); goto abort; } rc = shpc_indirect_read(ctrl, 3, &tempdword); if (rc) { err("%s: cannot read slot config\n", __func__); goto abort; } num_slots = tempdword & SLOT_NUM; dbg("%s: num_slots (indirect) %x\n", __func__, num_slots); for (i = 0; i < 9 + num_slots; i++) { rc = shpc_indirect_read(ctrl, i, &tempdword); if (rc) { err("%s: cannot read creg (index = %d)\n", __func__, i); goto abort; } dbg("%s: offset %d: value %x\n", __func__,i, tempdword); } ctrl->mmio_base = pci_resource_start(pdev, 0) + shpc_base_offset; ctrl->mmio_size = 0x24 + 0x4 * num_slots; } info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device); rc = pci_enable_device(pdev); if (rc) { err("%s: pci_enable_device failed\n", __func__); goto abort; } if (!request_mem_region(ctrl->mmio_base, ctrl->mmio_size, MY_NAME)) { err("%s: cannot reserve MMIO region\n", __func__); rc = -1; goto abort; } ctrl->creg = ioremap(ctrl->mmio_base, ctrl->mmio_size); if (!ctrl->creg) { err("%s: cannot remap MMIO region %lx @ %lx\n", __func__, ctrl->mmio_size, ctrl->mmio_base); release_mem_region(ctrl->mmio_base, ctrl->mmio_size); rc = -1; goto abort; } dbg("%s: ctrl->creg %p\n", __func__, ctrl->creg); mutex_init(&ctrl->crit_sect); mutex_init(&ctrl->cmd_lock); /* Setup wait queue */ init_waitqueue_head(&ctrl->queue); ctrl->hpc_ops = &shpchp_hpc_ops; /* Return PCI Controller Info */ slot_config = shpc_readl(ctrl, SLOT_CONFIG); ctrl->slot_device_offset = (slot_config & FIRST_DEV_NUM) >> 8; ctrl->num_slots = slot_config & SLOT_NUM; ctrl->first_slot = (slot_config & PSN) >> 16; ctrl->slot_num_inc = ((slot_config & UPDOWN) >> 29) ? 1 : -1; /* Mask Global Interrupt Mask & Command Complete Interrupt Mask */ tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); dbg("%s: SERR_INTR_ENABLE = %x\n", __func__, tempdword); tempdword |= (GLOBAL_INTR_MASK | GLOBAL_SERR_MASK | COMMAND_INTR_MASK | ARBITER_SERR_MASK); tempdword &= ~SERR_INTR_RSVDZ_MASK; shpc_writel(ctrl, SERR_INTR_ENABLE, tempdword); tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); dbg("%s: SERR_INTR_ENABLE = %x\n", __func__, tempdword); /* Mask the MRL sensor SERR Mask of individual slot in * Slot SERR-INT Mask & clear all the existing event if any */ for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); dbg("%s: Default Logical Slot Register %d value %x\n", __func__, hp_slot, slot_reg); slot_reg |= (PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK | BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK | CON_PFAULT_INTR_MASK | MRL_CHANGE_SERR_MASK | CON_PFAULT_SERR_MASK); slot_reg &= ~SLOT_REG_RSVDZ_MASK; shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg); } if (shpchp_poll_mode) { /* Install interrupt polling timer. Start with 10 sec delay */ init_timer(&ctrl->poll_timer); start_int_poll_timer(ctrl, 10); } else { /* Installs the interrupt handler */ rc = pci_enable_msi(pdev); if (rc) { info("Can't get msi for the hotplug controller\n"); info("Use INTx for the hotplug controller\n"); } rc = request_irq(ctrl->pci_dev->irq, shpc_isr, IRQF_SHARED, MY_NAME, (void *)ctrl); dbg("%s: request_irq %d for hpc%d (returns %d)\n", __func__, ctrl->pci_dev->irq, atomic_read(&shpchp_num_controllers), rc); if (rc) { err("Can't get irq %d for the hotplug controller\n", ctrl->pci_dev->irq); goto abort_iounmap; } } dbg("%s: HPC at b:d:f:irq=0x%x:%x:%x:%x\n", __func__, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pdev->irq); /* * If this is the first controller to be initialized, * initialize the shpchpd work queue */ if (atomic_add_return(1, &shpchp_num_controllers) == 1) { shpchp_wq = create_singlethread_workqueue("shpchpd"); if (!shpchp_wq) { rc = -ENOMEM; goto abort_iounmap; } } /* * Unmask all event interrupts of all slots */ for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); dbg("%s: Default Logical Slot Register %d value %x\n", __func__, hp_slot, slot_reg); slot_reg &= ~(PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK | BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK | CON_PFAULT_INTR_MASK | SLOT_REG_RSVDZ_MASK); shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg); } if (!shpchp_poll_mode) { /* Unmask all general input interrupts and SERR */ tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); tempdword &= ~(GLOBAL_INTR_MASK | COMMAND_INTR_MASK | SERR_INTR_RSVDZ_MASK); shpc_writel(ctrl, SERR_INTR_ENABLE, tempdword); tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE); dbg("%s: SERR_INTR_ENABLE = %x\n", __func__, tempdword); } return 0; /* We end up here for the many possible ways to fail this API. */abort_iounmap: iounmap(ctrl->creg);abort: return rc;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -