diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index 3fc889944f02..6ae5b27e27b3 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -373,12 +373,14 @@ static const struct dw_pcie_host_ops dra7xx_pcie_host_ops = { .init = dra7xx_pcie_host_init, }; -static void dra7xx_pcie_ep_init(struct dw_pcie_ep *ep) +static int dra7xx_pcie_ep_init(struct dw_pcie_ep *ep) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci); dra7xx_pcie_enable_wrapper_interrupts(dra7xx); + + return 0; } static void dra7xx_pcie_raise_intx_irq(struct dra7xx_pcie *dra7xx) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 278d2dba1db0..20f5b236af00 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -876,7 +876,7 @@ static const struct dw_pcie_ops ks_pcie_dw_pcie_ops = { .write_dbi2 = ks_pcie_am654_write_dbi2, }; -static void ks_pcie_am654_ep_init(struct dw_pcie_ep *ep) +static int ks_pcie_am654_ep_init(struct dw_pcie_ep *ep) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); int flags; @@ -885,6 +885,8 @@ static void ks_pcie_am654_ep_init(struct dw_pcie_ep *ep) flags = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_32; dw_pcie_writel_dbi2(pci, PCI_BASE_ADDRESS_0, APP_ADDR_SPACE_0 - 1); dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, flags); + + return 0; } static void ks_pcie_am654_raise_intx_irq(struct keystone_pcie *ks_pcie) diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index 8936975ff104..527c57114dcf 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -147,7 +147,7 @@ ls_pcie_ep_get_features(struct dw_pcie_ep *ep) return pcie->ls_epc; } -static void ls_pcie_ep_init(struct dw_pcie_ep *ep) +static int ls_pcie_ep_init(struct dw_pcie_ep *ep) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci); @@ -155,10 +155,12 @@ static void ls_pcie_ep_init(struct dw_pcie_ep *ep) ep_func = dw_pcie_ep_get_func_from_ep(ep, 0); if (!ep_func) - return; + return -ENODEV; pcie->ls_epc->msi_capable = ep_func->msi_cap ? true : false; pcie->ls_epc->msix_capable = ep_func->msix_cap ? true : false; + + return 0; } static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c index 5cd227dda9a1..7f0ba506dd1c 100644 --- a/drivers/pci/controller/dwc/pcie-artpec6.c +++ b/drivers/pci/controller/dwc/pcie-artpec6.c @@ -335,7 +335,7 @@ static const struct dw_pcie_host_ops artpec6_pcie_host_ops = { .init = artpec6_pcie_host_init, }; -static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep) +static int artpec6_pcie_ep_init(struct dw_pcie_ep *ep) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci); @@ -344,6 +344,8 @@ static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep) artpec6_pcie_init_phy(artpec6_pcie); artpec6_pcie_deassert_core_reset(artpec6_pcie); artpec6_pcie_wait_for_phy(artpec6_pcie); + + return 0; } static int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 31402ae218c7..de8ee3db4360 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -1032,6 +1032,8 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, * there is no unified way to check if we have operations in * flight, thus we don't know if we should WARN() or not. */ + /* flush posted write before unmap */ + readl(ep->msi_mem + ep->msi_iatu_mapped_offset); dw_pcie_ep_unmap_addr(epc, func_no, 0, ep->msi_mem_phys); ep->msi_iatu_mapped = false; } @@ -1044,6 +1046,7 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, return ret; ep->msi_iatu_mapped = true; + ep->msi_iatu_mapped_offset = offset; ep->msi_msg_addr = msg_addr; ep->msi_map_size = map_size; } @@ -1124,6 +1127,17 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, return -EPERM; } + /* + * ep->msi_iatu_mapped means that an MSI target address is cached, + * unmap it first so that we can reuse ep->msi_mem_phys for MSI-X. + */ + if (ep->msi_iatu_mapped) { + /* flush posted write before unmap */ + readl(ep->msi_mem + ep->msi_iatu_mapped_offset); + dw_pcie_ep_unmap_addr(epc, func_no, 0, ep->msi_mem_phys); + ep->msi_iatu_mapped = false; + } + msg_addr = dw_pcie_ep_align_addr(epc, msg_addr, &map_size, &offset); ret = dw_pcie_ep_map_addr(epc, func_no, 0, ep->msi_mem_phys, msg_addr, map_size); @@ -1372,8 +1386,11 @@ int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep) list_add_tail(&ep_func->list, &ep->func_list); } - if (ep->ops->init) - ep->ops->init(ep); + if (ep->ops->init) { + ret = ep->ops->init(ep); + if (ret) + goto err_remove_edma; + } dw_pcie_ep_disable_bars(ep); @@ -1526,8 +1543,11 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) if (ret) return ret; - if (ep->ops->pre_init) - ep->ops->pre_init(ep); + if (ep->ops->pre_init) { + ret = ep->ops->pre_init(ep); + if (ret) + return ret; + } ret = pci_epc_mem_init(epc, ep->phys_base, ep->addr_size, ep->page_size); diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index ec4722ed9303..593388f29bdd 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -842,8 +842,10 @@ EXPORT_SYMBOL_GPL(dw_pcie_upconfig_setup); static void dw_pcie_link_set_max_speed(struct dw_pcie *pci) { - u32 cap, ctrl2, link_speed; + u32 cap, ctrl2; + enum pci_bus_speed link_speed; u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); + u16 ctrl2_speed; cap = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP); @@ -860,30 +862,18 @@ static void dw_pcie_link_set_max_speed(struct dw_pcie *pci) ctrl2 = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCTL2); ctrl2 &= ~PCI_EXP_LNKCTL2_TLS; - switch (pcie_get_link_speed(pci->max_link_speed)) { - case PCIE_SPEED_2_5GT: - link_speed = PCI_EXP_LNKCTL2_TLS_2_5GT; - break; - case PCIE_SPEED_5_0GT: - link_speed = PCI_EXP_LNKCTL2_TLS_5_0GT; - break; - case PCIE_SPEED_8_0GT: - link_speed = PCI_EXP_LNKCTL2_TLS_8_0GT; - break; - case PCIE_SPEED_16_0GT: - link_speed = PCI_EXP_LNKCTL2_TLS_16_0GT; - break; - default: + link_speed = pcie_get_link_speed(pci->max_link_speed); + ctrl2_speed = pci_bus_speed2lnkctl2(link_speed); + if (ctrl2_speed == 0) { /* Use hardware capability */ - link_speed = FIELD_GET(PCI_EXP_LNKCAP_SLS, cap); + ctrl2_speed = FIELD_GET(PCI_EXP_LNKCAP_SLS, cap); ctrl2 &= ~PCI_EXP_LNKCTL2_HASD; - break; } - dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCTL2, ctrl2 | link_speed); + dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCTL2, ctrl2 | ctrl2_speed); cap &= ~((u32)PCI_EXP_LNKCAP_SLS); - dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, cap | link_speed); + dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, cap | ctrl2_speed); } diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index de4b245b1758..0735ae940924 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -474,8 +474,8 @@ struct dw_pcie_rp { }; struct dw_pcie_ep_ops { - void (*pre_init)(struct dw_pcie_ep *ep); - void (*init)(struct dw_pcie_ep *ep); + int (*pre_init)(struct dw_pcie_ep *ep); + int (*init)(struct dw_pcie_ep *ep); int (*raise_irq)(struct dw_pcie_ep *ep, u8 func_no, unsigned int type, u16 interrupt_num); const struct pci_epc_features* (*get_features)(struct dw_pcie_ep *ep); @@ -518,6 +518,7 @@ struct dw_pcie_ep { /* MSI outbound iATU state */ bool msi_iatu_mapped; + size_t msi_iatu_mapped_offset; u64 msi_msg_addr; size_t msi_map_size; }; diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index f9efe2d44957..af26a07c0c9e 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -474,12 +474,14 @@ static void rockchip_pcie_ep_hide_broken_ats_cap_rk3588(struct dw_pcie_ep *ep) dw_pcie_remove_ext_capability(pci, PCI_EXT_CAP_ID_ATS); } -static void rockchip_pcie_ep_init(struct dw_pcie_ep *ep) +static int rockchip_pcie_ep_init(struct dw_pcie_ep *ep) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); rockchip_pcie_enable_l0s(pci); rockchip_pcie_ep_hide_broken_ats_cap_rk3588(ep); + + return 0; }; static int rockchip_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, diff --git a/drivers/pci/controller/dwc/pcie-keembay.c b/drivers/pci/controller/dwc/pcie-keembay.c index 2459c4d66b88..6e126d5f75dc 100644 --- a/drivers/pci/controller/dwc/pcie-keembay.c +++ b/drivers/pci/controller/dwc/pcie-keembay.c @@ -279,12 +279,14 @@ static int keembay_pcie_setup_msi_irq(struct keembay_pcie *pcie) return 0; } -static void keembay_pcie_ep_init(struct dw_pcie_ep *ep) +static int keembay_pcie_ep_init(struct dw_pcie_ep *ep) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct keembay_pcie *pcie = dev_get_drvdata(pci->dev); writel(EDMA_INT_EN, pcie->apb_base + PCIE_REGS_INTERRUPT_ENABLE); + + return 0; } static int keembay_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c index 8b03c42f8c84..55ef0da9146c 100644 --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c @@ -373,7 +373,7 @@ static void rcar_gen4_remove_dw_pcie_rp(struct rcar_gen4_pcie *rcar) } /* Endpoint mode */ -static void rcar_gen4_pcie_ep_pre_init(struct dw_pcie_ep *ep) +static int rcar_gen4_pcie_ep_pre_init(struct dw_pcie_ep *ep) { struct dw_pcie *dw = to_dw_pcie_from_ep(ep); struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw); @@ -381,9 +381,11 @@ static void rcar_gen4_pcie_ep_pre_init(struct dw_pcie_ep *ep) ret = rcar_gen4_pcie_common_init(rcar); if (ret) - return; + return ret; writel(PCIEDMAINTSTSEN_INIT, rcar->base + PCIEDMAINTSTSEN); + + return 0; } static void rcar_gen4_pcie_ep_deinit(struct rcar_gen4_pcie *rcar) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 27ab97894c8a..ba3c3fddddc2 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -2,6 +2,7 @@ #ifndef DRIVERS_PCI_H #define DRIVERS_PCI_H +#include #include #include #include @@ -620,6 +621,28 @@ void pci_bus_put(struct pci_bus *bus); (speed) == PCIE_SPEED_2_5GT ? 2500*8/10 : \ 0) +static inline bool pcie_valid_speed(enum pci_bus_speed speed) +{ + return (speed >= PCIE_SPEED_2_5GT) && (speed <= PCIE_SPEED_64_0GT); +} + +static inline u16 pci_bus_speed2lnkctl2(enum pci_bus_speed speed) +{ + static const u8 speed_conv[] = { + [PCIE_SPEED_2_5GT] = PCI_EXP_LNKCTL2_TLS_2_5GT, + [PCIE_SPEED_5_0GT] = PCI_EXP_LNKCTL2_TLS_5_0GT, + [PCIE_SPEED_8_0GT] = PCI_EXP_LNKCTL2_TLS_8_0GT, + [PCIE_SPEED_16_0GT] = PCI_EXP_LNKCTL2_TLS_16_0GT, + [PCIE_SPEED_32_0GT] = PCI_EXP_LNKCTL2_TLS_32_0GT, + [PCIE_SPEED_64_0GT] = PCI_EXP_LNKCTL2_TLS_64_0GT, + }; + + if (WARN_ON_ONCE(!pcie_valid_speed(speed))) + return 0; + + return speed_conv[speed]; +} + static inline int pcie_dev_speed_mbps(enum pci_bus_speed speed) { switch (speed) { diff --git a/drivers/pci/pcie/bwctrl.c b/drivers/pci/pcie/bwctrl.c index c4c8d260bf96..d48021bfd844 100644 --- a/drivers/pci/pcie/bwctrl.c +++ b/drivers/pci/pcie/bwctrl.c @@ -48,28 +48,6 @@ struct pcie_bwctrl_data { /* Prevent port removal during Link Speed changes. */ static DECLARE_RWSEM(pcie_bwctrl_setspeed_rwsem); -static bool pcie_valid_speed(enum pci_bus_speed speed) -{ - return (speed >= PCIE_SPEED_2_5GT) && (speed <= PCIE_SPEED_64_0GT); -} - -static u16 pci_bus_speed2lnkctl2(enum pci_bus_speed speed) -{ - static const u8 speed_conv[] = { - [PCIE_SPEED_2_5GT] = PCI_EXP_LNKCTL2_TLS_2_5GT, - [PCIE_SPEED_5_0GT] = PCI_EXP_LNKCTL2_TLS_5_0GT, - [PCIE_SPEED_8_0GT] = PCI_EXP_LNKCTL2_TLS_8_0GT, - [PCIE_SPEED_16_0GT] = PCI_EXP_LNKCTL2_TLS_16_0GT, - [PCIE_SPEED_32_0GT] = PCI_EXP_LNKCTL2_TLS_32_0GT, - [PCIE_SPEED_64_0GT] = PCI_EXP_LNKCTL2_TLS_64_0GT, - }; - - if (WARN_ON_ONCE(!pcie_valid_speed(speed))) - return 0; - - return speed_conv[speed]; -} - static inline u16 pcie_supported_speeds2target_speed(u8 supported_speeds) { return __fls(supported_speeds);