Loading drivers/pci/host/pci-msm.c +347 −266 Original line number Diff line number Diff line Loading @@ -579,6 +579,10 @@ struct msm_pcie_dev_t { bool l0s_supported; bool l1_supported; bool l1ss_supported; bool l1_1_pcipm_supported; bool l1_2_pcipm_supported; bool l1_1_aspm_supported; bool l1_2_aspm_supported; bool common_clk_en; bool clk_power_manage_en; bool aux_clk_sync; Loading Loading @@ -881,15 +885,19 @@ static const struct msm_pcie_irq_info_t msm_pcie_msi_info[MSM_PCIE_MAX_MSI] = { }; static void msm_pcie_config_sid(struct msm_pcie_dev_t *dev); static int msm_pcie_config_device(struct pci_dev *dev, void *pdev); static int msm_pcie_config_l0s_disable(struct pci_dev *dev, void *pdev); static int msm_pcie_config_l0s_enable(struct pci_dev *dev, void *pdev); static int msm_pcie_config_l1_disable(struct pci_dev *dev, void *pdev); static int msm_pcie_config_l1_enable(struct pci_dev *dev, void *pdev); static int msm_pcie_config_l1ss_disable(struct pci_dev *dev, void *pdev); static int msm_pcie_config_l1ss_enable(struct pci_dev *dev, void *pdev); static void msm_pcie_config_link_pm_rc(struct msm_pcie_dev_t *dev, struct pci_dev *pdev, bool enable); static void msm_pcie_config_l0s_disable_all(struct msm_pcie_dev_t *dev, struct pci_bus *bus); static void msm_pcie_config_l1_disable_all(struct msm_pcie_dev_t *dev, struct pci_bus *bus); static void msm_pcie_config_l1ss_disable_all(struct msm_pcie_dev_t *dev, struct pci_bus *bus); static void msm_pcie_config_l0s_enable_all(struct msm_pcie_dev_t *dev); static void msm_pcie_config_l1_enable_all(struct msm_pcie_dev_t *dev); static void msm_pcie_config_l1ss_enable_all(struct msm_pcie_dev_t *dev); static void msm_pcie_check_l1ss_support_all(struct msm_pcie_dev_t *dev); static void msm_pcie_config_link_pm(struct msm_pcie_dev_t *dev, bool enable); #ifdef CONFIG_ARM static inline void msm_pcie_fixup_irqs(struct msm_pcie_dev_t *dev) Loading Loading @@ -1199,6 +1207,14 @@ static void msm_pcie_show_status(struct msm_pcie_dev_t *dev) dev->l1_supported ? "" : "not"); PCIE_DBG_FS(dev, "l1ss_supported is %s supported\n", dev->l1ss_supported ? "" : "not"); PCIE_DBG_FS(dev, "l1_1_pcipm_supported is %s supported\n", dev->l1_1_pcipm_supported ? "" : "not"); PCIE_DBG_FS(dev, "l1_2_pcipm_supported is %s supported\n", dev->l1_2_pcipm_supported ? "" : "not"); PCIE_DBG_FS(dev, "l1_1_aspm_supported is %s supported\n", dev->l1_1_aspm_supported ? "" : "not"); PCIE_DBG_FS(dev, "l1_2_aspm_supported is %s supported\n", dev->l1_2_aspm_supported ? "" : "not"); PCIE_DBG_FS(dev, "common_clk_en is %d\n", dev->common_clk_en); PCIE_DBG_FS(dev, "clk_power_manage_en is %d\n", Loading Loading @@ -1397,46 +1413,22 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev, case MSM_PCIE_DISABLE_L0S: PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: disable L0s\n\n", dev->rc_idx); if (dev->link_status == MSM_PCIE_LINK_ENABLED) { struct pci_bus *bus, *c_bus; struct list_head *children = &dev->dev->bus->children; msm_pcie_config_l0s_disable(dev->dev, dev); list_for_each_entry_safe(bus, c_bus, children, node) pci_walk_bus(bus, &msm_pcie_config_l0s_disable, dev); } if (dev->link_status == MSM_PCIE_LINK_ENABLED) msm_pcie_config_l0s_disable_all(dev, dev->dev->bus); dev->l0s_supported = false; break; case MSM_PCIE_ENABLE_L0S: PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: enable L0s\n\n", dev->rc_idx); dev->l0s_supported = true; if (dev->link_status == MSM_PCIE_LINK_ENABLED) { struct pci_bus *bus, *c_bus; struct list_head *children = &dev->dev->bus->children; list_for_each_entry_safe(bus, c_bus, children, node) pci_walk_bus(bus, &msm_pcie_config_l0s_enable, dev); msm_pcie_config_l0s_enable(dev->dev, dev); } if (dev->link_status == MSM_PCIE_LINK_ENABLED) msm_pcie_config_l0s_enable_all(dev); break; case MSM_PCIE_DISABLE_L1: PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: disable L1\n\n", dev->rc_idx); if (dev->link_status == MSM_PCIE_LINK_ENABLED) { struct pci_bus *bus, *c_bus; struct list_head *children = &dev->dev->bus->children; msm_pcie_config_l1_disable(dev->dev, dev); list_for_each_entry_safe(bus, c_bus, children, node) pci_walk_bus(bus, &msm_pcie_config_l1_disable, dev); } if (dev->link_status == MSM_PCIE_LINK_ENABLED) msm_pcie_config_l1_disable_all(dev, dev->dev->bus); dev->l1_supported = false; break; case MSM_PCIE_ENABLE_L1: Loading @@ -1444,48 +1436,35 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev, dev->rc_idx); dev->l1_supported = true; if (dev->link_status == MSM_PCIE_LINK_ENABLED) { struct pci_bus *bus, *c_bus; struct list_head *children = &dev->dev->bus->children; list_for_each_entry_safe(bus, c_bus, children, node) pci_walk_bus(bus, &msm_pcie_config_l1_enable, dev); /* enable l1 mode, clear bit 5 (REQ_NOT_ENTR_L1) */ msm_pcie_write_mask(dev->parf + PCIE20_PARF_PM_CTRL, BIT(5), 0); msm_pcie_config_l1_enable(dev->dev, dev); msm_pcie_config_l1_enable_all(dev); } break; case MSM_PCIE_DISABLE_L1SS: PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: disable L1ss\n\n", dev->rc_idx); if (dev->link_status == MSM_PCIE_LINK_ENABLED) { struct pci_bus *bus, *c_bus; struct list_head *children = &dev->dev->bus->children; msm_pcie_config_l1ss_disable(dev->dev, dev); list_for_each_entry_safe(bus, c_bus, children, node) pci_walk_bus(bus, &msm_pcie_config_l1ss_disable, dev); } if (dev->link_status == MSM_PCIE_LINK_ENABLED) msm_pcie_config_l1ss_disable_all(dev, dev->dev->bus); dev->l1ss_supported = false; dev->l1_1_pcipm_supported = false; dev->l1_2_pcipm_supported = false; dev->l1_1_aspm_supported = false; dev->l1_2_aspm_supported = false; break; case MSM_PCIE_ENABLE_L1SS: PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: enable L1ss\n\n", dev->rc_idx); dev->l1ss_supported = true; dev->l1_1_pcipm_supported = true; dev->l1_2_pcipm_supported = true; dev->l1_1_aspm_supported = true; dev->l1_2_aspm_supported = true; if (dev->link_status == MSM_PCIE_LINK_ENABLED) { struct pci_bus *bus, *c_bus; struct list_head *children = &dev->dev->bus->children; list_for_each_entry_safe(bus, c_bus, children, node) pci_walk_bus(bus, &msm_pcie_config_l1ss_enable, dev); msm_pcie_config_l1ss_enable(dev->dev, dev); msm_pcie_check_l1ss_support_all(dev); msm_pcie_config_l1ss_enable_all(dev); } break; case MSM_PCIE_ENUMERATION: Loading Loading @@ -4087,10 +4066,8 @@ static int msm_pcie_enable(struct msm_pcie_dev_t *dev, u32 options) if (!dev->msi_gicm_addr) msm_pcie_config_msi_controller(dev); if (dev->enumerated) { pci_walk_bus(dev->dev->bus, &msm_pcie_config_device, dev); msm_pcie_config_link_pm_rc(dev, dev->dev, true); } if (dev->enumerated) msm_pcie_config_link_pm(dev, true); goto out; Loading Loading @@ -4516,7 +4493,8 @@ int msm_pcie_enumerate(u32 rc_idx) goto out; } msm_pcie_config_link_pm_rc(dev, dev->dev, true); msm_pcie_check_l1ss_support_all(dev); msm_pcie_config_link_pm(dev, true); } else { PCIE_ERR(dev, "PCIe: failed to enable RC%d.\n", dev->rc_idx); Loading Loading @@ -5441,38 +5419,219 @@ static void msm_pcie_irq_deinit(struct msm_pcie_dev_t *dev) disable_irq(dev->wake_n); } static bool msm_pcie_check_l0s_support(struct pci_dev *pdev, struct msm_pcie_dev_t *pcie_dev) { struct pci_dev *parent = pdev->bus->self; u32 val; /* check parent supports L0s */ if (parent) { u32 val2; pci_read_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCAP, &val); pci_read_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCTL, &val2); val = (val & BIT(10)) && (val2 & PCI_EXP_LNKCTL_ASPM_L0S); if (!val) { PCIE_DBG(pcie_dev, "PCIe: RC%d: Parent PCI device %02x:%02x.%01x does not support L0s\n", pcie_dev->rc_idx, parent->bus->number, PCI_SLOT(parent->devfn), PCI_FUNC(parent->devfn)); return false; } } pci_read_config_dword(pdev, pdev->pcie_cap + PCI_EXP_LNKCAP, &val); if (!(val & BIT(10))) { PCIE_DBG(pcie_dev, "PCIe: RC%d: PCI device %02x:%02x.%01x does not support L0s\n", pcie_dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); return false; } return true; } static bool msm_pcie_check_l1_support(struct pci_dev *pdev, struct msm_pcie_dev_t *pcie_dev) { struct pci_dev *parent = pdev->bus->self; u32 val; /* check parent supports L1 */ if (parent) { u32 val2; pci_read_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCAP, &val); pci_read_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCTL, &val2); val = (val & BIT(11)) && (val2 & PCI_EXP_LNKCTL_ASPM_L1); if (!val) { PCIE_DBG(pcie_dev, "PCIe: RC%d: Parent PCI device %02x:%02x.%01x does not support L1\n", pcie_dev->rc_idx, parent->bus->number, PCI_SLOT(parent->devfn), PCI_FUNC(parent->devfn)); return false; } } pci_read_config_dword(pdev, pdev->pcie_cap + PCI_EXP_LNKCAP, &val); if (!(val & BIT(11))) { PCIE_DBG(pcie_dev, "PCIe: RC%d: PCI device %02x:%02x.%01x does not support L1\n", pcie_dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); return false; } return true; } static int msm_pcie_check_l1ss_support(struct pci_dev *pdev, void *dev) { struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev; u32 val; u32 l1ss_cap_id_offset, l1ss_cap_offset, l1ss_ctl1_offset; if (!pcie_dev->l1ss_supported) return -ENXIO; l1ss_cap_id_offset = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS); if (!l1ss_cap_id_offset) { PCIE_DBG(pcie_dev, "PCIe: RC%d: PCI device %02x:%02x.%01x could not find L1ss capability register\n", pcie_dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); pcie_dev->l1ss_supported = 0; return -ENXIO; } l1ss_cap_offset = l1ss_cap_id_offset + PCI_L1SS_CAP; l1ss_ctl1_offset = l1ss_cap_id_offset + PCI_L1SS_CTL1; pci_read_config_dword(pdev, l1ss_cap_offset, &val); pcie_dev->l1_1_pcipm_supported &= !!(val & (PCI_L1SS_CAP_PCIPM_L1_1)); pcie_dev->l1_2_pcipm_supported &= !!(val & (PCI_L1SS_CAP_PCIPM_L1_2)); pcie_dev->l1_1_aspm_supported &= !!(val & (PCI_L1SS_CAP_ASPM_L1_1)); pcie_dev->l1_2_aspm_supported &= !!(val & (PCI_L1SS_CAP_ASPM_L1_2)); if (!pcie_dev->l1_1_pcipm_supported && !pcie_dev->l1_2_pcipm_supported && !pcie_dev->l1_1_aspm_supported && !pcie_dev->l1_2_aspm_supported) { PCIE_DBG(pcie_dev, "PCIe: RC%d: PCI device %02x:%02x.%01x does not support any L1ss\n", pcie_dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); pcie_dev->l1ss_supported = 0; return -ENXIO; } return 0; } static int msm_pcie_config_common_clock_enable(struct pci_dev *pdev, void *dev) { struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev; PCIE_DBG(pcie_dev, "PCIe: RC%d: PCI device %02x:%02x.%01x\n", pcie_dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); msm_pcie_config_clear_set_dword(pdev, pdev->pcie_cap + PCI_EXP_LNKCTL, 0, PCI_EXP_LNKCTL_CCC); return 0; } static void msm_pcie_config_common_clock_enable_all(struct msm_pcie_dev_t *dev) { if (dev->common_clk_en) pci_walk_bus(dev->dev->bus, msm_pcie_config_common_clock_enable, dev); } static int msm_pcie_config_clock_power_management_enable(struct pci_dev *pdev, void *dev) { struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev; u32 val; /* enable only for upstream ports */ if (pci_is_root_bus(pdev->bus)) return 0; PCIE_DBG(pcie_dev, "PCIe: RC%d: PCI device %02x:%02x.%01x\n", pcie_dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); pci_read_config_dword(pdev, pdev->pcie_cap + PCI_EXP_LNKCAP, &val); if (val & PCI_EXP_LNKCAP_CLKPM) msm_pcie_config_clear_set_dword(pdev, pdev->pcie_cap + PCI_EXP_LNKCTL, 0, PCI_EXP_LNKCTL_CLKREQ_EN); else PCIE_DBG(pcie_dev, "PCIe: RC%d: PCI device %02x:%02x.%01x does not support clock power management\n", pcie_dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); return 0; } static void msm_pcie_config_clock_power_management_enable_all( struct msm_pcie_dev_t *dev) { if (dev->clk_power_manage_en) pci_walk_bus(dev->dev->bus, msm_pcie_config_clock_power_management_enable, dev); } static void msm_pcie_config_l0s(struct msm_pcie_dev_t *dev, struct pci_dev *pdev, bool enable) { u32 val; u32 lnkcap_offset = pdev->pcie_cap + PCI_EXP_LNKCAP; u32 lnkctl_offset = pdev->pcie_cap + PCI_EXP_LNKCTL; int ret; pci_read_config_dword(pdev, lnkcap_offset, &val); if (!(val & BIT(10))) { PCIE_DBG(dev, "PCIe: RC%d: PCI device does not support L0s\n", dev->rc_idx); PCIE_DBG(dev, "PCIe: RC%d: PCI device %02x:%02x.%01x %s\n", dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), enable ? "enable" : "disable"); if (enable) { ret = msm_pcie_check_l0s_support(pdev, dev); if (!ret) return; } if (enable) msm_pcie_config_clear_set_dword(pdev, lnkctl_offset, 0, PCI_EXP_LNKCTL_ASPM_L0S); else } else { msm_pcie_config_clear_set_dword(pdev, lnkctl_offset, PCI_EXP_LNKCTL_ASPM_L0S, 0); pci_read_config_dword(pdev, lnkctl_offset, &val); PCIE_DBG2(dev, "PCIe: RC%d: LINKCTRLSTATUS:0x%x\n", dev->rc_idx, val); } } static int msm_pcie_config_l0s_disable(struct pci_dev *pdev, void *dev) static void msm_pcie_config_l0s_disable_all(struct msm_pcie_dev_t *dev, struct pci_bus *bus) { struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev; struct pci_dev *pdev; msm_pcie_config_l0s(pcie_dev, pdev, false); return 0; if (!dev->l0s_supported) return; list_for_each_entry(pdev, &bus->devices, bus_list) { struct pci_bus *child; child = pdev->subordinate; if (child) msm_pcie_config_l0s_disable_all(dev, child); msm_pcie_config_l0s(dev, pdev, false); } } static int msm_pcie_config_l0s_enable(struct pci_dev *pdev, void *dev) Loading @@ -5483,38 +5642,51 @@ static int msm_pcie_config_l0s_enable(struct pci_dev *pdev, void *dev) return 0; } static void msm_pcie_config_l0s_enable_all(struct msm_pcie_dev_t *dev) { if (dev->l0s_supported) pci_walk_bus(dev->dev->bus, msm_pcie_config_l0s_enable, dev); } static void msm_pcie_config_l1(struct msm_pcie_dev_t *dev, struct pci_dev *pdev, bool enable) { u32 val; u32 lnkcap_offset = pdev->pcie_cap + PCI_EXP_LNKCAP; u32 lnkctl_offset = pdev->pcie_cap + PCI_EXP_LNKCTL; int ret; pci_read_config_dword(pdev, lnkcap_offset, &val); if (!(val & BIT(11))) { PCIE_DBG(dev, "PCIe: RC%d: PCI device does not support L1\n", dev->rc_idx); PCIE_DBG(dev, "PCIe: RC%d: PCI device %02x:%02x.%01x %s\n", dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), enable ? "enable" : "disable"); if (enable) { ret = msm_pcie_check_l1_support(pdev, dev); if (!ret) return; } if (enable) msm_pcie_config_clear_set_dword(pdev, lnkctl_offset, 0, PCI_EXP_LNKCTL_ASPM_L1); else } else { msm_pcie_config_clear_set_dword(pdev, lnkctl_offset, PCI_EXP_LNKCTL_ASPM_L1, 0); pci_read_config_dword(pdev, lnkctl_offset, &val); PCIE_DBG2(dev, "PCIe: RC%d: LINKCTRLSTATUS:0x%x\n", dev->rc_idx, val); } } static int msm_pcie_config_l1_disable(struct pci_dev *pdev, void *dev) static void msm_pcie_config_l1_disable_all(struct msm_pcie_dev_t *dev, struct pci_bus *bus) { struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev; struct pci_dev *pdev; msm_pcie_config_l1(pcie_dev, pdev, false); return 0; if (!dev->l1_supported) return; list_for_each_entry(pdev, &bus->devices, bus_list) { struct pci_bus *child; child = pdev->subordinate; if (child) msm_pcie_config_l1_disable_all(dev, child); msm_pcie_config_l1(dev, pdev, false); } } static int msm_pcie_config_l1_enable(struct pci_dev *pdev, void *dev) Loading @@ -5525,39 +5697,34 @@ static int msm_pcie_config_l1_enable(struct pci_dev *pdev, void *dev) return 0; } static void msm_pcie_config_l1_enable_all(struct msm_pcie_dev_t *dev) { if (dev->l1_supported) pci_walk_bus(dev->dev->bus, msm_pcie_config_l1_enable, dev); } static void msm_pcie_config_l1ss(struct msm_pcie_dev_t *dev, struct pci_dev *pdev, bool enable) { bool l1_1_pcipm_support, l1_2_pcipm_support; bool l1_1_aspm_support, l1_2_aspm_support; u32 val, val2; u32 l1ss_cap_id_offset, l1ss_cap_offset, l1ss_ctl1_offset; u32 l1ss_cap_id_offset, l1ss_ctl1_offset; u32 devctl2_offset = pdev->pcie_cap + PCI_EXP_DEVCTL2; PCIE_DBG(dev, "PCIe: RC%d: PCI device %02x:%02x.%01x %s\n", dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), enable ? "enable" : "disable"); l1ss_cap_id_offset = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS); if (!l1ss_cap_id_offset) { PCIE_DBG(dev, "PCIe: RC%d could not find L1ss capability register for device\n", dev->rc_idx); "PCIe: RC%d: PCI device %02x:%02x.%01x could not find L1ss capability register\n", dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); return; } l1ss_cap_offset = l1ss_cap_id_offset + PCI_L1SS_CAP; l1ss_ctl1_offset = l1ss_cap_id_offset + PCI_L1SS_CTL1; pci_read_config_dword(pdev, l1ss_cap_offset, &val); l1_1_pcipm_support = !!(val & (PCI_L1SS_CAP_PCIPM_L1_1)); l1_2_pcipm_support = !!(val & (PCI_L1SS_CAP_PCIPM_L1_2)); l1_1_aspm_support = !!(val & (PCI_L1SS_CAP_ASPM_L1_1)); l1_2_aspm_support = !!(val & (PCI_L1SS_CAP_ASPM_L1_2)); if (!l1_1_pcipm_support && !l1_2_pcipm_support && !l1_1_aspm_support && !l1_2_aspm_support) { PCIE_DBG(dev, "PCIe: RC%d: PCI device does not support any L1ss\n", dev->rc_idx); return; } /* Enable the AUX Clock and the Core Clk to be synchronous for L1ss */ if (pci_is_root_bus(pdev->bus) && !dev->aux_clk_sync) { if (enable) Loading @@ -5571,19 +5738,23 @@ static void msm_pcie_config_l1ss(struct msm_pcie_dev_t *dev, if (enable) { msm_pcie_config_clear_set_dword(pdev, devctl2_offset, 0, PCI_EXP_DEVCTL2_LTR_EN); msm_pcie_config_clear_set_dword(pdev, l1ss_ctl1_offset, 0, (l1_1_pcipm_support ? PCI_L1SS_CTL1_PCIPM_L1_1 : 0) | (l1_2_pcipm_support ? PCI_L1SS_CTL1_PCIPM_L1_2 : 0) | (l1_1_aspm_support ? PCI_L1SS_CTL1_ASPM_L1_1 : 0) | (l1_2_aspm_support ? PCI_L1SS_CTL1_ASPM_L1_2 : 0)); (dev->l1_1_pcipm_supported ? PCI_L1SS_CTL1_PCIPM_L1_1 : 0) | (dev->l1_2_pcipm_supported ? PCI_L1SS_CTL1_PCIPM_L1_2 : 0) | (dev->l1_1_aspm_supported ? PCI_L1SS_CTL1_ASPM_L1_1 : 0) | (dev->l1_2_aspm_supported ? PCI_L1SS_CTL1_ASPM_L1_2 : 0)); } else { msm_pcie_config_clear_set_dword(pdev, devctl2_offset, PCI_EXP_DEVCTL2_LTR_EN, 0); msm_pcie_config_clear_set_dword(pdev, l1ss_ctl1_offset, (l1_1_pcipm_support ? PCI_L1SS_CTL1_PCIPM_L1_1 : 0) | (l1_2_pcipm_support ? PCI_L1SS_CTL1_PCIPM_L1_2 : 0) | (l1_1_aspm_support ? PCI_L1SS_CTL1_ASPM_L1_1 : 0) | (l1_2_aspm_support ? PCI_L1SS_CTL1_ASPM_L1_2 : 0), 0); PCI_L1SS_CTL1_PCIPM_L1_1 | PCI_L1SS_CTL1_PCIPM_L1_2 | PCI_L1SS_CTL1_ASPM_L1_1 | PCI_L1SS_CTL1_ASPM_L1_2, 0); } pci_read_config_dword(pdev, l1ss_ctl1_offset, &val); Loading @@ -5602,157 +5773,58 @@ static int msm_pcie_config_l1ss_disable(struct pci_dev *pdev, void *dev) return 0; } static int msm_pcie_config_l1ss_enable(struct pci_dev *pdev, void *dev) { struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev; msm_pcie_config_l1ss(pcie_dev, pdev, true); return 0; } static void msm_pcie_config_clock_power_management(struct msm_pcie_dev_t *dev, struct pci_dev *pdev) { u32 val; u32 lnkcap_offset = pdev->pcie_cap + PCI_EXP_LNKCAP; u32 lnkctl_offset = pdev->pcie_cap + PCI_EXP_LNKCTL; if (pci_is_root_bus(pdev->bus)) return; pci_read_config_dword(pdev, lnkcap_offset, &val); if (val & PCI_EXP_LNKCAP_CLKPM) msm_pcie_config_clear_set_dword(pdev, lnkctl_offset, 0, PCI_EXP_LNKCTL_CLKREQ_EN); else PCIE_DBG(dev, "PCIe: RC%d: PCI device does not support clock power management\n", dev->rc_idx); } static void msm_pcie_config_link_pm(struct msm_pcie_dev_t *dev, struct pci_dev *pdev, bool enable) { if (dev->common_clk_en) msm_pcie_config_clear_set_dword(pdev, pdev->pcie_cap + PCI_EXP_LNKCTL, 0, PCI_EXP_LNKCTL_CCC); if (dev->clk_power_manage_en) msm_pcie_config_clock_power_management(dev, pdev); if (dev->l0s_supported) msm_pcie_config_l0s(dev, pdev, enable); if (dev->l1ss_supported) msm_pcie_config_l1ss(dev, pdev, enable); if (dev->l1_supported) msm_pcie_config_l1(dev, pdev, enable); } static void msm_pcie_config_link_pm_rc(struct msm_pcie_dev_t *dev, struct pci_dev *pdev, bool enable) static void msm_pcie_config_l1ss_disable_all(struct msm_pcie_dev_t *dev, struct pci_bus *bus) { bool child_l0s_enable = 0, child_l1_enable = 0, child_l1ss_enable = 0; struct pci_dev *pdev; if (!pdev->subordinate) { PCIE_DBG(dev, "PCIe: RC%d: no device connected to root complex\n", dev->rc_idx); if (!dev->l1ss_supported) return; } if (dev->l0s_supported) { struct pci_dev *child_pdev, *c_pdev; list_for_each_entry_safe(child_pdev, c_pdev, &pdev->subordinate->devices, bus_list) { u32 val; list_for_each_entry(pdev, &bus->devices, bus_list) { struct pci_bus *child; pci_read_config_dword(child_pdev, child_pdev->pcie_cap + PCI_EXP_LNKCTL, &val); child_l0s_enable = !!(val & PCI_EXP_LNKCTL_ASPM_L0S); if (child_l0s_enable) break; child = pdev->subordinate; if (child) msm_pcie_config_l1ss_disable_all(dev, child); msm_pcie_config_l1ss_disable(pdev, dev); } if (child_l0s_enable) msm_pcie_config_l0s(dev, pdev, enable); else dev->l0s_supported = false; } if (dev->l1ss_supported) { struct pci_dev *child_pdev, *c_pdev; list_for_each_entry_safe(child_pdev, c_pdev, &pdev->subordinate->devices, bus_list) { u32 val; u32 l1ss_cap_id_offset = pci_find_ext_capability(child_pdev, PCI_EXT_CAP_ID_L1SS); if (!l1ss_cap_id_offset) continue; pci_read_config_dword(child_pdev, l1ss_cap_id_offset + PCI_L1SS_CTL1, &val); child_l1ss_enable = !!(val & (PCI_L1SS_CTL1_PCIPM_L1_1 | PCI_L1SS_CTL1_PCIPM_L1_2 | PCI_L1SS_CTL1_ASPM_L1_1 | PCI_L1SS_CTL1_ASPM_L1_2)); if (child_l1ss_enable) break; } if (child_l1ss_enable) msm_pcie_config_l1ss(dev, pdev, enable); else dev->l1ss_supported = false; } if (dev->l1_supported) { struct pci_dev *child_pdev, *c_pdev; list_for_each_entry_safe(child_pdev, c_pdev, &pdev->subordinate->devices, bus_list) { u32 val; static int msm_pcie_config_l1ss_enable(struct pci_dev *pdev, void *dev) { struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev; pci_read_config_dword(child_pdev, child_pdev->pcie_cap + PCI_EXP_LNKCTL, &val); child_l1_enable = !!(val & PCI_EXP_LNKCTL_ASPM_L1); if (child_l1_enable) break; msm_pcie_config_l1ss(pcie_dev, pdev, true); return 0; } if (child_l1_enable) msm_pcie_config_l1(dev, pdev, enable); else dev->l1_supported = false; } static void msm_pcie_config_l1ss_enable_all(struct msm_pcie_dev_t *dev) { if (dev->l1ss_supported) pci_walk_bus(dev->dev->bus, msm_pcie_config_l1ss_enable, dev); } static int msm_pcie_config_device(struct pci_dev *dev, void *pdev) static void msm_pcie_config_link_pm(struct msm_pcie_dev_t *dev, bool enable) { struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)pdev; u8 busnr = dev->bus->number; u8 slot = PCI_SLOT(dev->devfn); u8 func = PCI_FUNC(dev->devfn); PCIE_DBG(pcie_dev, "PCIe: RC%d: configure PCI device %02x:%02x.%01x\n", pcie_dev->rc_idx, busnr, slot, func); if (!pci_is_root_bus(dev->bus)) msm_pcie_config_link_pm(pcie_dev, dev, true); struct pci_bus *bus = dev->dev->bus; return 0; if (enable) { msm_pcie_config_common_clock_enable_all(dev); msm_pcie_config_clock_power_management_enable_all(dev); msm_pcie_config_l1ss_enable_all(dev); msm_pcie_config_l1_enable_all(dev); msm_pcie_config_l0s_enable_all(dev); } else { msm_pcie_config_l0s_disable_all(dev, bus); msm_pcie_config_l1_disable_all(dev, bus); msm_pcie_config_l1ss_disable_all(dev, bus); } } /* Hook to setup PCI device during PCI framework scan */ int pcibios_add_device(struct pci_dev *dev) static void msm_pcie_check_l1ss_support_all(struct msm_pcie_dev_t *dev) { struct msm_pcie_dev_t *pcie_dev = PCIE_BUS_PRIV_DATA(dev->bus); return msm_pcie_config_device(dev, pcie_dev); pci_walk_bus(dev->dev->bus, msm_pcie_check_l1ss_support, dev); } static int msm_pcie_probe(struct platform_device *pdev) Loading Loading @@ -5806,6 +5878,15 @@ static int msm_pcie_probe(struct platform_device *pdev) !msm_pcie_dev[rc_idx].l1ss_supported; PCIE_DBG(&msm_pcie_dev[rc_idx], "L1ss is %s supported.\n", msm_pcie_dev[rc_idx].l1ss_supported ? "" : "not"); msm_pcie_dev[rc_idx].l1_1_aspm_supported = msm_pcie_dev[rc_idx].l1ss_supported; msm_pcie_dev[rc_idx].l1_2_aspm_supported = msm_pcie_dev[rc_idx].l1ss_supported; msm_pcie_dev[rc_idx].l1_1_pcipm_supported = msm_pcie_dev[rc_idx].l1ss_supported; msm_pcie_dev[rc_idx].l1_1_pcipm_supported = msm_pcie_dev[rc_idx].l1ss_supported; msm_pcie_dev[rc_idx].common_clk_en = of_property_read_bool((&pdev->dev)->of_node, "qcom,common-clk-en"); Loading Loading
drivers/pci/host/pci-msm.c +347 −266 Original line number Diff line number Diff line Loading @@ -579,6 +579,10 @@ struct msm_pcie_dev_t { bool l0s_supported; bool l1_supported; bool l1ss_supported; bool l1_1_pcipm_supported; bool l1_2_pcipm_supported; bool l1_1_aspm_supported; bool l1_2_aspm_supported; bool common_clk_en; bool clk_power_manage_en; bool aux_clk_sync; Loading Loading @@ -881,15 +885,19 @@ static const struct msm_pcie_irq_info_t msm_pcie_msi_info[MSM_PCIE_MAX_MSI] = { }; static void msm_pcie_config_sid(struct msm_pcie_dev_t *dev); static int msm_pcie_config_device(struct pci_dev *dev, void *pdev); static int msm_pcie_config_l0s_disable(struct pci_dev *dev, void *pdev); static int msm_pcie_config_l0s_enable(struct pci_dev *dev, void *pdev); static int msm_pcie_config_l1_disable(struct pci_dev *dev, void *pdev); static int msm_pcie_config_l1_enable(struct pci_dev *dev, void *pdev); static int msm_pcie_config_l1ss_disable(struct pci_dev *dev, void *pdev); static int msm_pcie_config_l1ss_enable(struct pci_dev *dev, void *pdev); static void msm_pcie_config_link_pm_rc(struct msm_pcie_dev_t *dev, struct pci_dev *pdev, bool enable); static void msm_pcie_config_l0s_disable_all(struct msm_pcie_dev_t *dev, struct pci_bus *bus); static void msm_pcie_config_l1_disable_all(struct msm_pcie_dev_t *dev, struct pci_bus *bus); static void msm_pcie_config_l1ss_disable_all(struct msm_pcie_dev_t *dev, struct pci_bus *bus); static void msm_pcie_config_l0s_enable_all(struct msm_pcie_dev_t *dev); static void msm_pcie_config_l1_enable_all(struct msm_pcie_dev_t *dev); static void msm_pcie_config_l1ss_enable_all(struct msm_pcie_dev_t *dev); static void msm_pcie_check_l1ss_support_all(struct msm_pcie_dev_t *dev); static void msm_pcie_config_link_pm(struct msm_pcie_dev_t *dev, bool enable); #ifdef CONFIG_ARM static inline void msm_pcie_fixup_irqs(struct msm_pcie_dev_t *dev) Loading Loading @@ -1199,6 +1207,14 @@ static void msm_pcie_show_status(struct msm_pcie_dev_t *dev) dev->l1_supported ? "" : "not"); PCIE_DBG_FS(dev, "l1ss_supported is %s supported\n", dev->l1ss_supported ? "" : "not"); PCIE_DBG_FS(dev, "l1_1_pcipm_supported is %s supported\n", dev->l1_1_pcipm_supported ? "" : "not"); PCIE_DBG_FS(dev, "l1_2_pcipm_supported is %s supported\n", dev->l1_2_pcipm_supported ? "" : "not"); PCIE_DBG_FS(dev, "l1_1_aspm_supported is %s supported\n", dev->l1_1_aspm_supported ? "" : "not"); PCIE_DBG_FS(dev, "l1_2_aspm_supported is %s supported\n", dev->l1_2_aspm_supported ? "" : "not"); PCIE_DBG_FS(dev, "common_clk_en is %d\n", dev->common_clk_en); PCIE_DBG_FS(dev, "clk_power_manage_en is %d\n", Loading Loading @@ -1397,46 +1413,22 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev, case MSM_PCIE_DISABLE_L0S: PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: disable L0s\n\n", dev->rc_idx); if (dev->link_status == MSM_PCIE_LINK_ENABLED) { struct pci_bus *bus, *c_bus; struct list_head *children = &dev->dev->bus->children; msm_pcie_config_l0s_disable(dev->dev, dev); list_for_each_entry_safe(bus, c_bus, children, node) pci_walk_bus(bus, &msm_pcie_config_l0s_disable, dev); } if (dev->link_status == MSM_PCIE_LINK_ENABLED) msm_pcie_config_l0s_disable_all(dev, dev->dev->bus); dev->l0s_supported = false; break; case MSM_PCIE_ENABLE_L0S: PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: enable L0s\n\n", dev->rc_idx); dev->l0s_supported = true; if (dev->link_status == MSM_PCIE_LINK_ENABLED) { struct pci_bus *bus, *c_bus; struct list_head *children = &dev->dev->bus->children; list_for_each_entry_safe(bus, c_bus, children, node) pci_walk_bus(bus, &msm_pcie_config_l0s_enable, dev); msm_pcie_config_l0s_enable(dev->dev, dev); } if (dev->link_status == MSM_PCIE_LINK_ENABLED) msm_pcie_config_l0s_enable_all(dev); break; case MSM_PCIE_DISABLE_L1: PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: disable L1\n\n", dev->rc_idx); if (dev->link_status == MSM_PCIE_LINK_ENABLED) { struct pci_bus *bus, *c_bus; struct list_head *children = &dev->dev->bus->children; msm_pcie_config_l1_disable(dev->dev, dev); list_for_each_entry_safe(bus, c_bus, children, node) pci_walk_bus(bus, &msm_pcie_config_l1_disable, dev); } if (dev->link_status == MSM_PCIE_LINK_ENABLED) msm_pcie_config_l1_disable_all(dev, dev->dev->bus); dev->l1_supported = false; break; case MSM_PCIE_ENABLE_L1: Loading @@ -1444,48 +1436,35 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev, dev->rc_idx); dev->l1_supported = true; if (dev->link_status == MSM_PCIE_LINK_ENABLED) { struct pci_bus *bus, *c_bus; struct list_head *children = &dev->dev->bus->children; list_for_each_entry_safe(bus, c_bus, children, node) pci_walk_bus(bus, &msm_pcie_config_l1_enable, dev); /* enable l1 mode, clear bit 5 (REQ_NOT_ENTR_L1) */ msm_pcie_write_mask(dev->parf + PCIE20_PARF_PM_CTRL, BIT(5), 0); msm_pcie_config_l1_enable(dev->dev, dev); msm_pcie_config_l1_enable_all(dev); } break; case MSM_PCIE_DISABLE_L1SS: PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: disable L1ss\n\n", dev->rc_idx); if (dev->link_status == MSM_PCIE_LINK_ENABLED) { struct pci_bus *bus, *c_bus; struct list_head *children = &dev->dev->bus->children; msm_pcie_config_l1ss_disable(dev->dev, dev); list_for_each_entry_safe(bus, c_bus, children, node) pci_walk_bus(bus, &msm_pcie_config_l1ss_disable, dev); } if (dev->link_status == MSM_PCIE_LINK_ENABLED) msm_pcie_config_l1ss_disable_all(dev, dev->dev->bus); dev->l1ss_supported = false; dev->l1_1_pcipm_supported = false; dev->l1_2_pcipm_supported = false; dev->l1_1_aspm_supported = false; dev->l1_2_aspm_supported = false; break; case MSM_PCIE_ENABLE_L1SS: PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: enable L1ss\n\n", dev->rc_idx); dev->l1ss_supported = true; dev->l1_1_pcipm_supported = true; dev->l1_2_pcipm_supported = true; dev->l1_1_aspm_supported = true; dev->l1_2_aspm_supported = true; if (dev->link_status == MSM_PCIE_LINK_ENABLED) { struct pci_bus *bus, *c_bus; struct list_head *children = &dev->dev->bus->children; list_for_each_entry_safe(bus, c_bus, children, node) pci_walk_bus(bus, &msm_pcie_config_l1ss_enable, dev); msm_pcie_config_l1ss_enable(dev->dev, dev); msm_pcie_check_l1ss_support_all(dev); msm_pcie_config_l1ss_enable_all(dev); } break; case MSM_PCIE_ENUMERATION: Loading Loading @@ -4087,10 +4066,8 @@ static int msm_pcie_enable(struct msm_pcie_dev_t *dev, u32 options) if (!dev->msi_gicm_addr) msm_pcie_config_msi_controller(dev); if (dev->enumerated) { pci_walk_bus(dev->dev->bus, &msm_pcie_config_device, dev); msm_pcie_config_link_pm_rc(dev, dev->dev, true); } if (dev->enumerated) msm_pcie_config_link_pm(dev, true); goto out; Loading Loading @@ -4516,7 +4493,8 @@ int msm_pcie_enumerate(u32 rc_idx) goto out; } msm_pcie_config_link_pm_rc(dev, dev->dev, true); msm_pcie_check_l1ss_support_all(dev); msm_pcie_config_link_pm(dev, true); } else { PCIE_ERR(dev, "PCIe: failed to enable RC%d.\n", dev->rc_idx); Loading Loading @@ -5441,38 +5419,219 @@ static void msm_pcie_irq_deinit(struct msm_pcie_dev_t *dev) disable_irq(dev->wake_n); } static bool msm_pcie_check_l0s_support(struct pci_dev *pdev, struct msm_pcie_dev_t *pcie_dev) { struct pci_dev *parent = pdev->bus->self; u32 val; /* check parent supports L0s */ if (parent) { u32 val2; pci_read_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCAP, &val); pci_read_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCTL, &val2); val = (val & BIT(10)) && (val2 & PCI_EXP_LNKCTL_ASPM_L0S); if (!val) { PCIE_DBG(pcie_dev, "PCIe: RC%d: Parent PCI device %02x:%02x.%01x does not support L0s\n", pcie_dev->rc_idx, parent->bus->number, PCI_SLOT(parent->devfn), PCI_FUNC(parent->devfn)); return false; } } pci_read_config_dword(pdev, pdev->pcie_cap + PCI_EXP_LNKCAP, &val); if (!(val & BIT(10))) { PCIE_DBG(pcie_dev, "PCIe: RC%d: PCI device %02x:%02x.%01x does not support L0s\n", pcie_dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); return false; } return true; } static bool msm_pcie_check_l1_support(struct pci_dev *pdev, struct msm_pcie_dev_t *pcie_dev) { struct pci_dev *parent = pdev->bus->self; u32 val; /* check parent supports L1 */ if (parent) { u32 val2; pci_read_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCAP, &val); pci_read_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCTL, &val2); val = (val & BIT(11)) && (val2 & PCI_EXP_LNKCTL_ASPM_L1); if (!val) { PCIE_DBG(pcie_dev, "PCIe: RC%d: Parent PCI device %02x:%02x.%01x does not support L1\n", pcie_dev->rc_idx, parent->bus->number, PCI_SLOT(parent->devfn), PCI_FUNC(parent->devfn)); return false; } } pci_read_config_dword(pdev, pdev->pcie_cap + PCI_EXP_LNKCAP, &val); if (!(val & BIT(11))) { PCIE_DBG(pcie_dev, "PCIe: RC%d: PCI device %02x:%02x.%01x does not support L1\n", pcie_dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); return false; } return true; } static int msm_pcie_check_l1ss_support(struct pci_dev *pdev, void *dev) { struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev; u32 val; u32 l1ss_cap_id_offset, l1ss_cap_offset, l1ss_ctl1_offset; if (!pcie_dev->l1ss_supported) return -ENXIO; l1ss_cap_id_offset = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS); if (!l1ss_cap_id_offset) { PCIE_DBG(pcie_dev, "PCIe: RC%d: PCI device %02x:%02x.%01x could not find L1ss capability register\n", pcie_dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); pcie_dev->l1ss_supported = 0; return -ENXIO; } l1ss_cap_offset = l1ss_cap_id_offset + PCI_L1SS_CAP; l1ss_ctl1_offset = l1ss_cap_id_offset + PCI_L1SS_CTL1; pci_read_config_dword(pdev, l1ss_cap_offset, &val); pcie_dev->l1_1_pcipm_supported &= !!(val & (PCI_L1SS_CAP_PCIPM_L1_1)); pcie_dev->l1_2_pcipm_supported &= !!(val & (PCI_L1SS_CAP_PCIPM_L1_2)); pcie_dev->l1_1_aspm_supported &= !!(val & (PCI_L1SS_CAP_ASPM_L1_1)); pcie_dev->l1_2_aspm_supported &= !!(val & (PCI_L1SS_CAP_ASPM_L1_2)); if (!pcie_dev->l1_1_pcipm_supported && !pcie_dev->l1_2_pcipm_supported && !pcie_dev->l1_1_aspm_supported && !pcie_dev->l1_2_aspm_supported) { PCIE_DBG(pcie_dev, "PCIe: RC%d: PCI device %02x:%02x.%01x does not support any L1ss\n", pcie_dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); pcie_dev->l1ss_supported = 0; return -ENXIO; } return 0; } static int msm_pcie_config_common_clock_enable(struct pci_dev *pdev, void *dev) { struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev; PCIE_DBG(pcie_dev, "PCIe: RC%d: PCI device %02x:%02x.%01x\n", pcie_dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); msm_pcie_config_clear_set_dword(pdev, pdev->pcie_cap + PCI_EXP_LNKCTL, 0, PCI_EXP_LNKCTL_CCC); return 0; } static void msm_pcie_config_common_clock_enable_all(struct msm_pcie_dev_t *dev) { if (dev->common_clk_en) pci_walk_bus(dev->dev->bus, msm_pcie_config_common_clock_enable, dev); } static int msm_pcie_config_clock_power_management_enable(struct pci_dev *pdev, void *dev) { struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev; u32 val; /* enable only for upstream ports */ if (pci_is_root_bus(pdev->bus)) return 0; PCIE_DBG(pcie_dev, "PCIe: RC%d: PCI device %02x:%02x.%01x\n", pcie_dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); pci_read_config_dword(pdev, pdev->pcie_cap + PCI_EXP_LNKCAP, &val); if (val & PCI_EXP_LNKCAP_CLKPM) msm_pcie_config_clear_set_dword(pdev, pdev->pcie_cap + PCI_EXP_LNKCTL, 0, PCI_EXP_LNKCTL_CLKREQ_EN); else PCIE_DBG(pcie_dev, "PCIe: RC%d: PCI device %02x:%02x.%01x does not support clock power management\n", pcie_dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); return 0; } static void msm_pcie_config_clock_power_management_enable_all( struct msm_pcie_dev_t *dev) { if (dev->clk_power_manage_en) pci_walk_bus(dev->dev->bus, msm_pcie_config_clock_power_management_enable, dev); } static void msm_pcie_config_l0s(struct msm_pcie_dev_t *dev, struct pci_dev *pdev, bool enable) { u32 val; u32 lnkcap_offset = pdev->pcie_cap + PCI_EXP_LNKCAP; u32 lnkctl_offset = pdev->pcie_cap + PCI_EXP_LNKCTL; int ret; pci_read_config_dword(pdev, lnkcap_offset, &val); if (!(val & BIT(10))) { PCIE_DBG(dev, "PCIe: RC%d: PCI device does not support L0s\n", dev->rc_idx); PCIE_DBG(dev, "PCIe: RC%d: PCI device %02x:%02x.%01x %s\n", dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), enable ? "enable" : "disable"); if (enable) { ret = msm_pcie_check_l0s_support(pdev, dev); if (!ret) return; } if (enable) msm_pcie_config_clear_set_dword(pdev, lnkctl_offset, 0, PCI_EXP_LNKCTL_ASPM_L0S); else } else { msm_pcie_config_clear_set_dword(pdev, lnkctl_offset, PCI_EXP_LNKCTL_ASPM_L0S, 0); pci_read_config_dword(pdev, lnkctl_offset, &val); PCIE_DBG2(dev, "PCIe: RC%d: LINKCTRLSTATUS:0x%x\n", dev->rc_idx, val); } } static int msm_pcie_config_l0s_disable(struct pci_dev *pdev, void *dev) static void msm_pcie_config_l0s_disable_all(struct msm_pcie_dev_t *dev, struct pci_bus *bus) { struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev; struct pci_dev *pdev; msm_pcie_config_l0s(pcie_dev, pdev, false); return 0; if (!dev->l0s_supported) return; list_for_each_entry(pdev, &bus->devices, bus_list) { struct pci_bus *child; child = pdev->subordinate; if (child) msm_pcie_config_l0s_disable_all(dev, child); msm_pcie_config_l0s(dev, pdev, false); } } static int msm_pcie_config_l0s_enable(struct pci_dev *pdev, void *dev) Loading @@ -5483,38 +5642,51 @@ static int msm_pcie_config_l0s_enable(struct pci_dev *pdev, void *dev) return 0; } static void msm_pcie_config_l0s_enable_all(struct msm_pcie_dev_t *dev) { if (dev->l0s_supported) pci_walk_bus(dev->dev->bus, msm_pcie_config_l0s_enable, dev); } static void msm_pcie_config_l1(struct msm_pcie_dev_t *dev, struct pci_dev *pdev, bool enable) { u32 val; u32 lnkcap_offset = pdev->pcie_cap + PCI_EXP_LNKCAP; u32 lnkctl_offset = pdev->pcie_cap + PCI_EXP_LNKCTL; int ret; pci_read_config_dword(pdev, lnkcap_offset, &val); if (!(val & BIT(11))) { PCIE_DBG(dev, "PCIe: RC%d: PCI device does not support L1\n", dev->rc_idx); PCIE_DBG(dev, "PCIe: RC%d: PCI device %02x:%02x.%01x %s\n", dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), enable ? "enable" : "disable"); if (enable) { ret = msm_pcie_check_l1_support(pdev, dev); if (!ret) return; } if (enable) msm_pcie_config_clear_set_dword(pdev, lnkctl_offset, 0, PCI_EXP_LNKCTL_ASPM_L1); else } else { msm_pcie_config_clear_set_dword(pdev, lnkctl_offset, PCI_EXP_LNKCTL_ASPM_L1, 0); pci_read_config_dword(pdev, lnkctl_offset, &val); PCIE_DBG2(dev, "PCIe: RC%d: LINKCTRLSTATUS:0x%x\n", dev->rc_idx, val); } } static int msm_pcie_config_l1_disable(struct pci_dev *pdev, void *dev) static void msm_pcie_config_l1_disable_all(struct msm_pcie_dev_t *dev, struct pci_bus *bus) { struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev; struct pci_dev *pdev; msm_pcie_config_l1(pcie_dev, pdev, false); return 0; if (!dev->l1_supported) return; list_for_each_entry(pdev, &bus->devices, bus_list) { struct pci_bus *child; child = pdev->subordinate; if (child) msm_pcie_config_l1_disable_all(dev, child); msm_pcie_config_l1(dev, pdev, false); } } static int msm_pcie_config_l1_enable(struct pci_dev *pdev, void *dev) Loading @@ -5525,39 +5697,34 @@ static int msm_pcie_config_l1_enable(struct pci_dev *pdev, void *dev) return 0; } static void msm_pcie_config_l1_enable_all(struct msm_pcie_dev_t *dev) { if (dev->l1_supported) pci_walk_bus(dev->dev->bus, msm_pcie_config_l1_enable, dev); } static void msm_pcie_config_l1ss(struct msm_pcie_dev_t *dev, struct pci_dev *pdev, bool enable) { bool l1_1_pcipm_support, l1_2_pcipm_support; bool l1_1_aspm_support, l1_2_aspm_support; u32 val, val2; u32 l1ss_cap_id_offset, l1ss_cap_offset, l1ss_ctl1_offset; u32 l1ss_cap_id_offset, l1ss_ctl1_offset; u32 devctl2_offset = pdev->pcie_cap + PCI_EXP_DEVCTL2; PCIE_DBG(dev, "PCIe: RC%d: PCI device %02x:%02x.%01x %s\n", dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), enable ? "enable" : "disable"); l1ss_cap_id_offset = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS); if (!l1ss_cap_id_offset) { PCIE_DBG(dev, "PCIe: RC%d could not find L1ss capability register for device\n", dev->rc_idx); "PCIe: RC%d: PCI device %02x:%02x.%01x could not find L1ss capability register\n", dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); return; } l1ss_cap_offset = l1ss_cap_id_offset + PCI_L1SS_CAP; l1ss_ctl1_offset = l1ss_cap_id_offset + PCI_L1SS_CTL1; pci_read_config_dword(pdev, l1ss_cap_offset, &val); l1_1_pcipm_support = !!(val & (PCI_L1SS_CAP_PCIPM_L1_1)); l1_2_pcipm_support = !!(val & (PCI_L1SS_CAP_PCIPM_L1_2)); l1_1_aspm_support = !!(val & (PCI_L1SS_CAP_ASPM_L1_1)); l1_2_aspm_support = !!(val & (PCI_L1SS_CAP_ASPM_L1_2)); if (!l1_1_pcipm_support && !l1_2_pcipm_support && !l1_1_aspm_support && !l1_2_aspm_support) { PCIE_DBG(dev, "PCIe: RC%d: PCI device does not support any L1ss\n", dev->rc_idx); return; } /* Enable the AUX Clock and the Core Clk to be synchronous for L1ss */ if (pci_is_root_bus(pdev->bus) && !dev->aux_clk_sync) { if (enable) Loading @@ -5571,19 +5738,23 @@ static void msm_pcie_config_l1ss(struct msm_pcie_dev_t *dev, if (enable) { msm_pcie_config_clear_set_dword(pdev, devctl2_offset, 0, PCI_EXP_DEVCTL2_LTR_EN); msm_pcie_config_clear_set_dword(pdev, l1ss_ctl1_offset, 0, (l1_1_pcipm_support ? PCI_L1SS_CTL1_PCIPM_L1_1 : 0) | (l1_2_pcipm_support ? PCI_L1SS_CTL1_PCIPM_L1_2 : 0) | (l1_1_aspm_support ? PCI_L1SS_CTL1_ASPM_L1_1 : 0) | (l1_2_aspm_support ? PCI_L1SS_CTL1_ASPM_L1_2 : 0)); (dev->l1_1_pcipm_supported ? PCI_L1SS_CTL1_PCIPM_L1_1 : 0) | (dev->l1_2_pcipm_supported ? PCI_L1SS_CTL1_PCIPM_L1_2 : 0) | (dev->l1_1_aspm_supported ? PCI_L1SS_CTL1_ASPM_L1_1 : 0) | (dev->l1_2_aspm_supported ? PCI_L1SS_CTL1_ASPM_L1_2 : 0)); } else { msm_pcie_config_clear_set_dword(pdev, devctl2_offset, PCI_EXP_DEVCTL2_LTR_EN, 0); msm_pcie_config_clear_set_dword(pdev, l1ss_ctl1_offset, (l1_1_pcipm_support ? PCI_L1SS_CTL1_PCIPM_L1_1 : 0) | (l1_2_pcipm_support ? PCI_L1SS_CTL1_PCIPM_L1_2 : 0) | (l1_1_aspm_support ? PCI_L1SS_CTL1_ASPM_L1_1 : 0) | (l1_2_aspm_support ? PCI_L1SS_CTL1_ASPM_L1_2 : 0), 0); PCI_L1SS_CTL1_PCIPM_L1_1 | PCI_L1SS_CTL1_PCIPM_L1_2 | PCI_L1SS_CTL1_ASPM_L1_1 | PCI_L1SS_CTL1_ASPM_L1_2, 0); } pci_read_config_dword(pdev, l1ss_ctl1_offset, &val); Loading @@ -5602,157 +5773,58 @@ static int msm_pcie_config_l1ss_disable(struct pci_dev *pdev, void *dev) return 0; } static int msm_pcie_config_l1ss_enable(struct pci_dev *pdev, void *dev) { struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev; msm_pcie_config_l1ss(pcie_dev, pdev, true); return 0; } static void msm_pcie_config_clock_power_management(struct msm_pcie_dev_t *dev, struct pci_dev *pdev) { u32 val; u32 lnkcap_offset = pdev->pcie_cap + PCI_EXP_LNKCAP; u32 lnkctl_offset = pdev->pcie_cap + PCI_EXP_LNKCTL; if (pci_is_root_bus(pdev->bus)) return; pci_read_config_dword(pdev, lnkcap_offset, &val); if (val & PCI_EXP_LNKCAP_CLKPM) msm_pcie_config_clear_set_dword(pdev, lnkctl_offset, 0, PCI_EXP_LNKCTL_CLKREQ_EN); else PCIE_DBG(dev, "PCIe: RC%d: PCI device does not support clock power management\n", dev->rc_idx); } static void msm_pcie_config_link_pm(struct msm_pcie_dev_t *dev, struct pci_dev *pdev, bool enable) { if (dev->common_clk_en) msm_pcie_config_clear_set_dword(pdev, pdev->pcie_cap + PCI_EXP_LNKCTL, 0, PCI_EXP_LNKCTL_CCC); if (dev->clk_power_manage_en) msm_pcie_config_clock_power_management(dev, pdev); if (dev->l0s_supported) msm_pcie_config_l0s(dev, pdev, enable); if (dev->l1ss_supported) msm_pcie_config_l1ss(dev, pdev, enable); if (dev->l1_supported) msm_pcie_config_l1(dev, pdev, enable); } static void msm_pcie_config_link_pm_rc(struct msm_pcie_dev_t *dev, struct pci_dev *pdev, bool enable) static void msm_pcie_config_l1ss_disable_all(struct msm_pcie_dev_t *dev, struct pci_bus *bus) { bool child_l0s_enable = 0, child_l1_enable = 0, child_l1ss_enable = 0; struct pci_dev *pdev; if (!pdev->subordinate) { PCIE_DBG(dev, "PCIe: RC%d: no device connected to root complex\n", dev->rc_idx); if (!dev->l1ss_supported) return; } if (dev->l0s_supported) { struct pci_dev *child_pdev, *c_pdev; list_for_each_entry_safe(child_pdev, c_pdev, &pdev->subordinate->devices, bus_list) { u32 val; list_for_each_entry(pdev, &bus->devices, bus_list) { struct pci_bus *child; pci_read_config_dword(child_pdev, child_pdev->pcie_cap + PCI_EXP_LNKCTL, &val); child_l0s_enable = !!(val & PCI_EXP_LNKCTL_ASPM_L0S); if (child_l0s_enable) break; child = pdev->subordinate; if (child) msm_pcie_config_l1ss_disable_all(dev, child); msm_pcie_config_l1ss_disable(pdev, dev); } if (child_l0s_enable) msm_pcie_config_l0s(dev, pdev, enable); else dev->l0s_supported = false; } if (dev->l1ss_supported) { struct pci_dev *child_pdev, *c_pdev; list_for_each_entry_safe(child_pdev, c_pdev, &pdev->subordinate->devices, bus_list) { u32 val; u32 l1ss_cap_id_offset = pci_find_ext_capability(child_pdev, PCI_EXT_CAP_ID_L1SS); if (!l1ss_cap_id_offset) continue; pci_read_config_dword(child_pdev, l1ss_cap_id_offset + PCI_L1SS_CTL1, &val); child_l1ss_enable = !!(val & (PCI_L1SS_CTL1_PCIPM_L1_1 | PCI_L1SS_CTL1_PCIPM_L1_2 | PCI_L1SS_CTL1_ASPM_L1_1 | PCI_L1SS_CTL1_ASPM_L1_2)); if (child_l1ss_enable) break; } if (child_l1ss_enable) msm_pcie_config_l1ss(dev, pdev, enable); else dev->l1ss_supported = false; } if (dev->l1_supported) { struct pci_dev *child_pdev, *c_pdev; list_for_each_entry_safe(child_pdev, c_pdev, &pdev->subordinate->devices, bus_list) { u32 val; static int msm_pcie_config_l1ss_enable(struct pci_dev *pdev, void *dev) { struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev; pci_read_config_dword(child_pdev, child_pdev->pcie_cap + PCI_EXP_LNKCTL, &val); child_l1_enable = !!(val & PCI_EXP_LNKCTL_ASPM_L1); if (child_l1_enable) break; msm_pcie_config_l1ss(pcie_dev, pdev, true); return 0; } if (child_l1_enable) msm_pcie_config_l1(dev, pdev, enable); else dev->l1_supported = false; } static void msm_pcie_config_l1ss_enable_all(struct msm_pcie_dev_t *dev) { if (dev->l1ss_supported) pci_walk_bus(dev->dev->bus, msm_pcie_config_l1ss_enable, dev); } static int msm_pcie_config_device(struct pci_dev *dev, void *pdev) static void msm_pcie_config_link_pm(struct msm_pcie_dev_t *dev, bool enable) { struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)pdev; u8 busnr = dev->bus->number; u8 slot = PCI_SLOT(dev->devfn); u8 func = PCI_FUNC(dev->devfn); PCIE_DBG(pcie_dev, "PCIe: RC%d: configure PCI device %02x:%02x.%01x\n", pcie_dev->rc_idx, busnr, slot, func); if (!pci_is_root_bus(dev->bus)) msm_pcie_config_link_pm(pcie_dev, dev, true); struct pci_bus *bus = dev->dev->bus; return 0; if (enable) { msm_pcie_config_common_clock_enable_all(dev); msm_pcie_config_clock_power_management_enable_all(dev); msm_pcie_config_l1ss_enable_all(dev); msm_pcie_config_l1_enable_all(dev); msm_pcie_config_l0s_enable_all(dev); } else { msm_pcie_config_l0s_disable_all(dev, bus); msm_pcie_config_l1_disable_all(dev, bus); msm_pcie_config_l1ss_disable_all(dev, bus); } } /* Hook to setup PCI device during PCI framework scan */ int pcibios_add_device(struct pci_dev *dev) static void msm_pcie_check_l1ss_support_all(struct msm_pcie_dev_t *dev) { struct msm_pcie_dev_t *pcie_dev = PCIE_BUS_PRIV_DATA(dev->bus); return msm_pcie_config_device(dev, pcie_dev); pci_walk_bus(dev->dev->bus, msm_pcie_check_l1ss_support, dev); } static int msm_pcie_probe(struct platform_device *pdev) Loading Loading @@ -5806,6 +5878,15 @@ static int msm_pcie_probe(struct platform_device *pdev) !msm_pcie_dev[rc_idx].l1ss_supported; PCIE_DBG(&msm_pcie_dev[rc_idx], "L1ss is %s supported.\n", msm_pcie_dev[rc_idx].l1ss_supported ? "" : "not"); msm_pcie_dev[rc_idx].l1_1_aspm_supported = msm_pcie_dev[rc_idx].l1ss_supported; msm_pcie_dev[rc_idx].l1_2_aspm_supported = msm_pcie_dev[rc_idx].l1ss_supported; msm_pcie_dev[rc_idx].l1_1_pcipm_supported = msm_pcie_dev[rc_idx].l1ss_supported; msm_pcie_dev[rc_idx].l1_1_pcipm_supported = msm_pcie_dev[rc_idx].l1ss_supported; msm_pcie_dev[rc_idx].common_clk_en = of_property_read_bool((&pdev->dev)->of_node, "qcom,common-clk-en"); Loading