📄 pciehp_hpc.c
字号:
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; dbg("Max link width = %d\n", lnk_wdth); return retval;}static int hpc_get_cur_lnk_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, LNKSTATUS, &lnk_status); if (retval) { err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__); return retval; } switch (lnk_status & 0x0F) { case 1: lnk_speed = PCIE_2PT5GB; break; default: lnk_speed = PCIE_LNK_SPEED_UNKNOWN; break; } *value = lnk_speed; dbg("Current link speed = %d\n", lnk_speed); return retval;}static int hpc_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, LNKSTATUS, &lnk_status); if (retval) { err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__); return retval; } switch ((lnk_status & 0x03F0) >> 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; dbg("Current link width = %d\n", lnk_wdth); return retval;}static struct hpc_ops pciehp_hpc_ops = { .power_on_slot = hpc_power_on_slot, .power_off_slot = hpc_power_off_slot, .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_emi_status = hpc_get_emi_status, .toggle_emi = hpc_toggle_emi, .get_max_bus_speed = hpc_get_max_lnk_speed, .get_cur_bus_speed = hpc_get_cur_lnk_speed, .get_max_lnk_width = hpc_get_max_lnk_width, .get_cur_lnk_width = hpc_get_cur_lnk_width, .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, .check_lnk_status = hpc_check_lnk_status,};#ifdef CONFIG_ACPIint pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev){ acpi_status status; acpi_handle chandle, handle = DEVICE_ACPI_HANDLE(&(dev->dev)); struct pci_dev *pdev = dev; struct pci_bus *parent; struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL }; /* * Per PCI firmware specification, we should run the ACPI _OSC * method to get control of hotplug hardware before using it. * If an _OSC is missing, we look for an OSHP to do the same thing. * To handle different BIOS behavior, we look for _OSC and OSHP * within the scope of the hotplug controller and its parents, upto * the host bridge under which this controller exists. */ while (!handle) { /* * This hotplug controller was not listed in the ACPI name * space at all. Try to get acpi handle of parent pci bus. */ if (!pdev || !pdev->bus->parent) break; parent = pdev->bus->parent; dbg("Could not find %s in acpi namespace, trying parent\n", pci_name(pdev)); if (!parent->self) /* Parent must be a host bridge */ handle = acpi_get_pci_rootbridge_handle( pci_domain_nr(parent), parent->number); else handle = DEVICE_ACPI_HANDLE( &(parent->self->dev)); pdev = parent->self; } while (handle) { acpi_get_name(handle, ACPI_FULL_PATHNAME, &string); dbg("Trying to get hotplug control for %s \n", (char *)string.pointer); status = pci_osc_control_set(handle, OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL); if (status == AE_NOT_FOUND) status = acpi_run_oshp(handle); if (ACPI_SUCCESS(status)) { dbg("Gained control for hotplug HW for pci %s (%s)\n", pci_name(dev), (char *)string.pointer); kfree(string.pointer); return 0; } if (acpi_root_bridge(handle)) break; chandle = handle; status = acpi_get_parent(chandle, &handle); if (ACPI_FAILURE(status)) break; } err("Cannot get control of hotplug hardware for pci %s\n", pci_name(dev)); kfree(string.pointer); return -1;}#endifint pcie_init(struct controller * ctrl, struct pcie_device *dev){ int rc; u16 temp_word; u16 cap_reg; u16 intr_enable = 0; u32 slot_cap; int cap_base; u16 slot_status, slot_ctrl; struct pci_dev *pdev; pdev = dev->port; ctrl->pci_dev = pdev; /* save pci_dev in context */ dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n", __FUNCTION__, pdev->vendor, pdev->device); if ((cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP)) == 0) { dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__); goto abort_free_ctlr; } ctrl->cap_base = cap_base; dbg("%s: pcie_cap_base %x\n", __FUNCTION__, cap_base); rc = pciehp_readw(ctrl, CAPREG, &cap_reg); if (rc) { err("%s: Cannot read CAPREG register\n", __FUNCTION__); goto abort_free_ctlr; } dbg("%s: CAPREG offset %x cap_reg %x\n", __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg); if (((cap_reg & SLOT_IMPL) == 0) || (((cap_reg & DEV_PORT_TYPE) != 0x0040) && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) { dbg("%s : This is not a root port or the port is not " "connected to a slot\n", __FUNCTION__); goto abort_free_ctlr; } rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); if (rc) { err("%s: Cannot read SLOTCAP register\n", __FUNCTION__); goto abort_free_ctlr; } dbg("%s: SLOTCAP offset %x slot_cap %x\n", __FUNCTION__, ctrl->cap_base + SLOTCAP, slot_cap); if (!(slot_cap & HP_CAP)) { dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__); goto abort_free_ctlr; } /* For debugging purpose */ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (rc) { err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); goto abort_free_ctlr; } dbg("%s: SLOTSTATUS offset %x slot_status %x\n", __FUNCTION__, ctrl->cap_base + SLOTSTATUS, slot_status); rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (rc) { err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); goto abort_free_ctlr; } dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); for (rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) if (pci_resource_len(pdev, rc) > 0) dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc, (unsigned long long)pci_resource_start(pdev, rc), (unsigned long long)pci_resource_len(pdev, rc)); 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); mutex_init(&ctrl->crit_sect); mutex_init(&ctrl->ctrl_lock); spin_lock_init(&ctrl->lock); /* setup wait queue */ init_waitqueue_head(&ctrl->queue); /* return PCI Controller Info */ ctrl->slot_device_offset = 0; ctrl->num_slots = 1; ctrl->first_slot = slot_cap >> 19; ctrl->ctrlcap = slot_cap & 0x0000007f; /* Mask Hot-plug Interrupt Enable */ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); if (rc) { err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); goto abort_free_ctlr; } dbg("%s: SLOTCTRL %x value read %x\n", __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word); temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00; rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); if (rc) { err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); goto abort_free_ctlr; } rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (rc) { err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); goto abort_free_ctlr; } temp_word = 0x1F; /* Clear all events */ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); if (rc) { err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); goto abort_free_ctlr; } if (pciehp_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 = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED, MY_NAME, (void *)ctrl); dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, ctrl->pci_dev->irq, atomic_read(&pciehp_num_controllers), rc); if (rc) { err("Can't get irq %d for the hotplug controller\n", ctrl->pci_dev->irq); goto abort_free_ctlr; } } dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq); /* * If this is the first controller to be initialized, * initialize the pciehp work queue */ if (atomic_add_return(1, &pciehp_num_controllers) == 1) { pciehp_wq = create_singlethread_workqueue("pciehpd"); if (!pciehp_wq) { rc = -ENOMEM; goto abort_free_irq; } } rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); if (rc) { err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); goto abort_free_irq; } intr_enable = intr_enable | PRSN_DETECT_ENABLE; if (ATTN_BUTTN(slot_cap)) intr_enable = intr_enable | ATTN_BUTTN_ENABLE; if (POWER_CTRL(slot_cap)) intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE; if (MRL_SENS(slot_cap)) intr_enable = intr_enable | MRL_DETECT_ENABLE; temp_word = (temp_word & ~intr_enable) | intr_enable; if (pciehp_poll_mode) { temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0; } else { temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; } /* * Unmask Hot-plug Interrupt Enable for the interrupt * notification mechanism case. */ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); if (rc) { err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); goto abort_free_irq; } rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (rc) { err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); goto abort_disable_intr; } temp_word = 0x1F; /* Clear all events */ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); if (rc) { err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); goto abort_disable_intr; } if (pciehp_force) { dbg("Bypassing BIOS check for pciehp use on %s\n", pci_name(ctrl->pci_dev)); } else { rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev); if (rc) goto abort_disable_intr; } ctrl->hpc_ops = &pciehp_hpc_ops; return 0; /* We end up here for the many possible ways to fail this API. */abort_disable_intr: rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); if (!rc) { temp_word &= ~(intr_enable | HP_INTR_ENABLE); rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); } if (rc) err("%s : disabling interrupts failed\n", __FUNCTION__);abort_free_irq: if (pciehp_poll_mode) del_timer_sync(&ctrl->poll_timer); else free_irq(ctrl->pci_dev->irq, ctrl);abort_free_ctlr: return -1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -