Loading Documentation/devicetree/bindings/pci/msm_pcie.txt +4 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,8 @@ Optional Properties: - qti,l1ss-supported: L1 sub-states (L1ss) is supported. - qti,aux-clk-sync: The AUX clock is synchronous to the Core clock to support L1ss. - qcom,msi-gicm-addr: MSI address for GICv2m. - qcom,msi-gicm-base: MSI IRQ base for GICv2m. Example: Loading Loading @@ -107,4 +109,6 @@ Example: <0>, <0>, <0>, <0>; qti,l1ss-supported; qti,aux-clk-sync; qcom,msi-gicm-addr = <0xf9040040>; qcom,msi-gicm-base = <0x160>; }; arch/arm/mach-msm/pcie.c +27 −1 Original line number Diff line number Diff line Loading @@ -1044,6 +1044,7 @@ static int msm_pcie_enable(u32 rc_idx, u32 options) msm_pcie_config_controller(rc_idx); if (!dev->msi_gicm_addr) msm_pcie_config_msi_controller(dev); if (dev->l1ss_supported) Loading Loading @@ -1220,6 +1221,31 @@ static int msm_pcie_probe(struct platform_device *pdev) PCIE_DBG("AUX clock is %s synchronous to Core clock.\n", msm_pcie_dev[rc_idx].aux_clk_sync ? "" : "not"); msm_pcie_dev[rc_idx].msi_gicm_addr = 0; msm_pcie_dev[rc_idx].msi_gicm_base = 0; ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,msi-gicm-addr", &msm_pcie_dev[rc_idx].msi_gicm_addr); if (ret) { PCIE_DBG("msi-gicm-addr does not exist.\n"); } else { PCIE_DBG("msi-gicm-addr: 0x%x.\n", msm_pcie_dev[rc_idx].msi_gicm_addr); ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,msi-gicm-base", &msm_pcie_dev[rc_idx].msi_gicm_base); if (ret) { pr_err("msi-gicm-base does not exist.\n"); goto decrease_rc_num; } else { PCIE_DBG("msi-gicm-base: 0x%x.\n", msm_pcie_dev[rc_idx].msi_gicm_base); } } msm_pcie_dev[rc_idx].pdev = pdev; msm_pcie_dev[rc_idx].vreg_n = 0; msm_pcie_dev[rc_idx].gpio_n = 0; Loading arch/arm/mach-msm/pcie.h +2 −0 Original line number Diff line number Diff line Loading @@ -162,6 +162,8 @@ struct msm_pcie_dev_t { struct irq_domain *irq_domain; DECLARE_BITMAP(msi_irq_in_use, PCIE_MSI_NR_IRQS); uint32_t msi_gicm_addr; uint32_t msi_gicm_base; enum msm_pcie_link_status link_status; bool user_suspend; Loading arch/arm/mach-msm/pcie_irq.c +128 −5 Original line number Diff line number Diff line Loading @@ -97,7 +97,13 @@ void msm_pcie_destroy_irq(unsigned int irq) int pos; struct msm_pcie_dev_t *dev = irq_get_chip_data(irq); if (dev->msi_gicm_addr) { PCIE_DBG("destroy QGIC based irq\n"); pos = irq - dev->msi_gicm_base; } else { PCIE_DBG("destroy default MSI irq\n"); pos = irq - irq_find_mapping(dev->irq_domain, 0); } PCIE_DBG("\n"); Loading Loading @@ -150,8 +156,8 @@ again: return irq; } /* hookup to linux pci msi framework */ int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) static int arch_setup_msi_irq_default(struct pci_dev *pdev, struct msi_desc *desc, int nvec) { int irq; struct msi_msg msg; Loading @@ -160,6 +166,9 @@ int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) PCIE_DBG("\n"); irq = msm_pcie_create_irq(dev); PCIE_DBG("IRQ %d is allocated.\n", irq); if (irq < 0) return irq; Loading @@ -173,11 +182,125 @@ int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) msg.data = irq - irq_find_mapping(dev->irq_domain, 0); write_msi_msg(irq, &msg); irq_set_chip_and_handler(irq, &pcie_msi_chip, handle_simple_irq); set_irq_flags(irq, IRQF_VALID); return 0; } static int msm_pcie_create_irq_qgic(struct msm_pcie_dev_t *dev) { int irq, pos; PCIE_DBG("\n"); again: pos = find_first_zero_bit(dev->msi_irq_in_use, PCIE_MSI_NR_IRQS); if (pos >= PCIE_MSI_NR_IRQS) return -ENOSPC; if (test_and_set_bit(pos, dev->msi_irq_in_use)) goto again; irq = dev->msi_gicm_base + pos; if (!irq) { pr_err("PCIe: failed to create QGIC MSI IRQ.\n"); return -EINVAL; } return irq; } static int arch_setup_msi_irq_qgic(struct pci_dev *pdev, struct msi_desc *desc, int nvec) { int irq, index, firstirq = 0; struct msi_msg msg; struct msm_pcie_dev_t *dev = PCIE_BUS_PRIV_DATA(pdev); PCIE_DBG("\n"); for (index = 0; index < nvec; index++) { irq = msm_pcie_create_irq_qgic(dev); PCIE_DBG("irq %d is allocated\n", irq); if (irq < 0) return irq; if (index == 0) firstirq = irq; irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING); } /* write msi vector and data */ irq_set_msi_desc(firstirq, desc); msg.address_hi = 0; msg.address_lo = dev->msi_gicm_addr; msg.data = firstirq; write_msi_msg(firstirq, &msg); return 0; } int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) { struct msm_pcie_dev_t *dev = PCIE_BUS_PRIV_DATA(pdev); PCIE_DBG("\n"); if (dev->msi_gicm_addr) return arch_setup_msi_irq_qgic(pdev, desc, 1); else return arch_setup_msi_irq_default(pdev, desc, 1); } static int msm_pcie_get_msi_multiple(int nvec) { int msi_multiple = 0; PCIE_DBG("\n"); while (nvec) { nvec = nvec >> 1; msi_multiple++; } PCIE_DBG("log2 number of MSI multiple:%d\n", msi_multiple - 1); return msi_multiple - 1; } int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) { struct msi_desc *entry; int ret; struct msm_pcie_dev_t *pcie_dev = PCIE_BUS_PRIV_DATA(dev); PCIE_DBG("\n"); if (type != PCI_CAP_ID_MSI || nvec > 32) return -ENOSPC; PCIE_DBG("nvec = %d\n", nvec); list_for_each_entry(entry, &dev->msi_list, list) { entry->msi_attrib.multiple = msm_pcie_get_msi_multiple(nvec); if (pcie_dev->msi_gicm_addr) ret = arch_setup_msi_irq_qgic(dev, entry, nvec); else ret = arch_setup_msi_irq_default(dev, entry, nvec); PCIE_DBG("ret from msi_irq: %d\n", ret); if (ret < 0) return ret; if (ret > 0) return -ENOSPC; } return 0; } static int msm_pcie_msi_map(struct irq_domain *domain, unsigned int irq, irq_hw_number_t hwirq) Loading Loading
Documentation/devicetree/bindings/pci/msm_pcie.txt +4 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,8 @@ Optional Properties: - qti,l1ss-supported: L1 sub-states (L1ss) is supported. - qti,aux-clk-sync: The AUX clock is synchronous to the Core clock to support L1ss. - qcom,msi-gicm-addr: MSI address for GICv2m. - qcom,msi-gicm-base: MSI IRQ base for GICv2m. Example: Loading Loading @@ -107,4 +109,6 @@ Example: <0>, <0>, <0>, <0>; qti,l1ss-supported; qti,aux-clk-sync; qcom,msi-gicm-addr = <0xf9040040>; qcom,msi-gicm-base = <0x160>; };
arch/arm/mach-msm/pcie.c +27 −1 Original line number Diff line number Diff line Loading @@ -1044,6 +1044,7 @@ static int msm_pcie_enable(u32 rc_idx, u32 options) msm_pcie_config_controller(rc_idx); if (!dev->msi_gicm_addr) msm_pcie_config_msi_controller(dev); if (dev->l1ss_supported) Loading Loading @@ -1220,6 +1221,31 @@ static int msm_pcie_probe(struct platform_device *pdev) PCIE_DBG("AUX clock is %s synchronous to Core clock.\n", msm_pcie_dev[rc_idx].aux_clk_sync ? "" : "not"); msm_pcie_dev[rc_idx].msi_gicm_addr = 0; msm_pcie_dev[rc_idx].msi_gicm_base = 0; ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,msi-gicm-addr", &msm_pcie_dev[rc_idx].msi_gicm_addr); if (ret) { PCIE_DBG("msi-gicm-addr does not exist.\n"); } else { PCIE_DBG("msi-gicm-addr: 0x%x.\n", msm_pcie_dev[rc_idx].msi_gicm_addr); ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,msi-gicm-base", &msm_pcie_dev[rc_idx].msi_gicm_base); if (ret) { pr_err("msi-gicm-base does not exist.\n"); goto decrease_rc_num; } else { PCIE_DBG("msi-gicm-base: 0x%x.\n", msm_pcie_dev[rc_idx].msi_gicm_base); } } msm_pcie_dev[rc_idx].pdev = pdev; msm_pcie_dev[rc_idx].vreg_n = 0; msm_pcie_dev[rc_idx].gpio_n = 0; Loading
arch/arm/mach-msm/pcie.h +2 −0 Original line number Diff line number Diff line Loading @@ -162,6 +162,8 @@ struct msm_pcie_dev_t { struct irq_domain *irq_domain; DECLARE_BITMAP(msi_irq_in_use, PCIE_MSI_NR_IRQS); uint32_t msi_gicm_addr; uint32_t msi_gicm_base; enum msm_pcie_link_status link_status; bool user_suspend; Loading
arch/arm/mach-msm/pcie_irq.c +128 −5 Original line number Diff line number Diff line Loading @@ -97,7 +97,13 @@ void msm_pcie_destroy_irq(unsigned int irq) int pos; struct msm_pcie_dev_t *dev = irq_get_chip_data(irq); if (dev->msi_gicm_addr) { PCIE_DBG("destroy QGIC based irq\n"); pos = irq - dev->msi_gicm_base; } else { PCIE_DBG("destroy default MSI irq\n"); pos = irq - irq_find_mapping(dev->irq_domain, 0); } PCIE_DBG("\n"); Loading Loading @@ -150,8 +156,8 @@ again: return irq; } /* hookup to linux pci msi framework */ int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) static int arch_setup_msi_irq_default(struct pci_dev *pdev, struct msi_desc *desc, int nvec) { int irq; struct msi_msg msg; Loading @@ -160,6 +166,9 @@ int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) PCIE_DBG("\n"); irq = msm_pcie_create_irq(dev); PCIE_DBG("IRQ %d is allocated.\n", irq); if (irq < 0) return irq; Loading @@ -173,11 +182,125 @@ int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) msg.data = irq - irq_find_mapping(dev->irq_domain, 0); write_msi_msg(irq, &msg); irq_set_chip_and_handler(irq, &pcie_msi_chip, handle_simple_irq); set_irq_flags(irq, IRQF_VALID); return 0; } static int msm_pcie_create_irq_qgic(struct msm_pcie_dev_t *dev) { int irq, pos; PCIE_DBG("\n"); again: pos = find_first_zero_bit(dev->msi_irq_in_use, PCIE_MSI_NR_IRQS); if (pos >= PCIE_MSI_NR_IRQS) return -ENOSPC; if (test_and_set_bit(pos, dev->msi_irq_in_use)) goto again; irq = dev->msi_gicm_base + pos; if (!irq) { pr_err("PCIe: failed to create QGIC MSI IRQ.\n"); return -EINVAL; } return irq; } static int arch_setup_msi_irq_qgic(struct pci_dev *pdev, struct msi_desc *desc, int nvec) { int irq, index, firstirq = 0; struct msi_msg msg; struct msm_pcie_dev_t *dev = PCIE_BUS_PRIV_DATA(pdev); PCIE_DBG("\n"); for (index = 0; index < nvec; index++) { irq = msm_pcie_create_irq_qgic(dev); PCIE_DBG("irq %d is allocated\n", irq); if (irq < 0) return irq; if (index == 0) firstirq = irq; irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING); } /* write msi vector and data */ irq_set_msi_desc(firstirq, desc); msg.address_hi = 0; msg.address_lo = dev->msi_gicm_addr; msg.data = firstirq; write_msi_msg(firstirq, &msg); return 0; } int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) { struct msm_pcie_dev_t *dev = PCIE_BUS_PRIV_DATA(pdev); PCIE_DBG("\n"); if (dev->msi_gicm_addr) return arch_setup_msi_irq_qgic(pdev, desc, 1); else return arch_setup_msi_irq_default(pdev, desc, 1); } static int msm_pcie_get_msi_multiple(int nvec) { int msi_multiple = 0; PCIE_DBG("\n"); while (nvec) { nvec = nvec >> 1; msi_multiple++; } PCIE_DBG("log2 number of MSI multiple:%d\n", msi_multiple - 1); return msi_multiple - 1; } int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) { struct msi_desc *entry; int ret; struct msm_pcie_dev_t *pcie_dev = PCIE_BUS_PRIV_DATA(dev); PCIE_DBG("\n"); if (type != PCI_CAP_ID_MSI || nvec > 32) return -ENOSPC; PCIE_DBG("nvec = %d\n", nvec); list_for_each_entry(entry, &dev->msi_list, list) { entry->msi_attrib.multiple = msm_pcie_get_msi_multiple(nvec); if (pcie_dev->msi_gicm_addr) ret = arch_setup_msi_irq_qgic(dev, entry, nvec); else ret = arch_setup_msi_irq_default(dev, entry, nvec); PCIE_DBG("ret from msi_irq: %d\n", ret); if (ret < 0) return ret; if (ret > 0) return -ENOSPC; } return 0; } static int msm_pcie_msi_map(struct irq_domain *domain, unsigned int irq, irq_hw_number_t hwirq) Loading