mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 20:54:03 +02:00
Merge branch 'pci/controller/dwc'
- Factor pcie_valid_speed() and pci_bus_speed2lnkctl2() out of bwctrl so they can be shared by the DWC core (Hans Zhang) - Flush MSI writes from endpoint before unmapping the iATU, as we already do for MSI-X writes (Niklas Cassel) - Unmap MSI iATU window before mapping MSI-X window, to avoid a subsequent MSI write using a disabled aperture and losing the interrupt (Niklas Cassel) - Change endpoint .pre_init() and .init() callbacks to return errors and handle them (Marek Vasut) * pci/controller/dwc: PCI: dwc: Handle return value from endpoint .pre_init callback PCI: dwc: Handle return value from endpoint .init callback PCI: dwc: ep: Fix unmap potentially unmapping the wrong iATU PCI: dwc: ep: Flush cached MSI write before unmapping the iATU PCI: dwc: Use common speed conversion function PCI: Move pci_bus_speed2lnkctl2() to public header PCI: Add public pcie_valid_speed() for shared validation
This commit is contained in:
commit
71aabbe6d4
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#ifndef DRIVERS_PCI_H
|
||||
#define DRIVERS_PCI_H
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/align.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/pci.h>
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user