mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 10:33:41 +02:00
Merge branch 'pci/capability-search'
- Simplify __pci_find_next_cap_ttl() by replacing magic numbers with #defines, extracting fields with FIELD_GET(), etc (Hans Zhang) - Convert __pci_find_next_cap_ttl() to a PCI_FIND_NEXT_CAP() macro that takes a config space accessor function so we can also use it in cases where the usual config accessors aren't available (Hans Zhang) - Similarly convert pci_find_next_ext_capability() to a PCI_FIND_NEXT_EXT_CAP() macro (Hans Zhang) - Implement dwc, dwc endpoint, and cadence capability search interfaces on top of PCI_FIND_NEXT_CAP() and PCI_FIND_NEXT_EXT_CAP(), replacing the previous duplicated code (Hans Zhang) - Search for capabilities in the cadence core instead of hard-coding their offsets, which are subject to change (Hans Zhang) * pci/capability-search: PCI: cadence: Use cdns_pcie_find_*capability() to avoid hardcoding offsets PCI: cadence: Implement capability search using PCI core APIs PCI: dwc: ep: Implement capability search using PCI core APIs PCI: dwc: Implement capability search using PCI core APIs PCI: Refactor extended capability search into PCI_FIND_NEXT_EXT_CAP() PCI: Refactor capability search into PCI_FIND_NEXT_CAP() PCI: Clean up __pci_find_next_cap_ttl() readability
This commit is contained in:
commit
fef3530379
|
|
@ -21,12 +21,13 @@
|
|||
|
||||
static u8 cdns_pcie_get_fn_from_vfn(struct cdns_pcie *pcie, u8 fn, u8 vfn)
|
||||
{
|
||||
u32 cap = CDNS_PCIE_EP_FUNC_SRIOV_CAP_OFFSET;
|
||||
u32 first_vf_offset, stride;
|
||||
u16 cap;
|
||||
|
||||
if (vfn == 0)
|
||||
return fn;
|
||||
|
||||
cap = cdns_pcie_find_ext_capability(pcie, PCI_EXT_CAP_ID_SRIOV);
|
||||
first_vf_offset = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_SRIOV_VF_OFFSET);
|
||||
stride = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_SRIOV_VF_STRIDE);
|
||||
fn = fn + first_vf_offset + ((vfn - 1) * stride);
|
||||
|
|
@ -38,10 +39,11 @@ static int cdns_pcie_ep_write_header(struct pci_epc *epc, u8 fn, u8 vfn,
|
|||
struct pci_epf_header *hdr)
|
||||
{
|
||||
struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
u32 cap = CDNS_PCIE_EP_FUNC_SRIOV_CAP_OFFSET;
|
||||
struct cdns_pcie *pcie = &ep->pcie;
|
||||
u32 reg;
|
||||
u16 cap;
|
||||
|
||||
cap = cdns_pcie_find_ext_capability(pcie, PCI_EXT_CAP_ID_SRIOV);
|
||||
if (vfn > 1) {
|
||||
dev_err(&epc->dev, "Only Virtual Function #1 has deviceID\n");
|
||||
return -EINVAL;
|
||||
|
|
@ -227,9 +229,10 @@ static int cdns_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 vfn, u8 nr_irqs)
|
|||
struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct cdns_pcie *pcie = &ep->pcie;
|
||||
u8 mmc = order_base_2(nr_irqs);
|
||||
u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
|
||||
u16 flags;
|
||||
u8 cap;
|
||||
|
||||
cap = cdns_pcie_find_capability(pcie, PCI_CAP_ID_MSI);
|
||||
fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn);
|
||||
|
||||
/*
|
||||
|
|
@ -249,9 +252,10 @@ static int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn, u8 vfn)
|
|||
{
|
||||
struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct cdns_pcie *pcie = &ep->pcie;
|
||||
u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
|
||||
u16 flags, mme;
|
||||
u8 cap;
|
||||
|
||||
cap = cdns_pcie_find_capability(pcie, PCI_CAP_ID_MSIX);
|
||||
fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn);
|
||||
|
||||
/* Validate that the MSI feature is actually enabled. */
|
||||
|
|
@ -272,9 +276,10 @@ static int cdns_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no)
|
|||
{
|
||||
struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct cdns_pcie *pcie = &ep->pcie;
|
||||
u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
|
||||
u32 val, reg;
|
||||
u8 cap;
|
||||
|
||||
cap = cdns_pcie_find_capability(pcie, PCI_CAP_ID_MSIX);
|
||||
func_no = cdns_pcie_get_fn_from_vfn(pcie, func_no, vfunc_no);
|
||||
|
||||
reg = cap + PCI_MSIX_FLAGS;
|
||||
|
|
@ -292,9 +297,10 @@ static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u8 vfn,
|
|||
{
|
||||
struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct cdns_pcie *pcie = &ep->pcie;
|
||||
u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
|
||||
u32 val, reg;
|
||||
u8 cap;
|
||||
|
||||
cap = cdns_pcie_find_capability(pcie, PCI_CAP_ID_MSIX);
|
||||
fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn);
|
||||
|
||||
reg = cap + PCI_MSIX_FLAGS;
|
||||
|
|
@ -380,11 +386,11 @@ static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn, u8 vfn,
|
|||
u8 interrupt_num)
|
||||
{
|
||||
struct cdns_pcie *pcie = &ep->pcie;
|
||||
u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
|
||||
u16 flags, mme, data, data_mask;
|
||||
u8 msi_count;
|
||||
u64 pci_addr, pci_addr_mask = 0xff;
|
||||
u8 msi_count, cap;
|
||||
|
||||
cap = cdns_pcie_find_capability(pcie, PCI_CAP_ID_MSI);
|
||||
fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn);
|
||||
|
||||
/* Check whether the MSI feature has been enabled by the PCI host. */
|
||||
|
|
@ -432,14 +438,14 @@ static int cdns_pcie_ep_map_msi_irq(struct pci_epc *epc, u8 fn, u8 vfn,
|
|||
u32 *msi_addr_offset)
|
||||
{
|
||||
struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
|
||||
struct cdns_pcie *pcie = &ep->pcie;
|
||||
u64 pci_addr, pci_addr_mask = 0xff;
|
||||
u16 flags, mme, data, data_mask;
|
||||
u8 msi_count;
|
||||
u8 msi_count, cap;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
cap = cdns_pcie_find_capability(pcie, PCI_CAP_ID_MSI);
|
||||
fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn);
|
||||
|
||||
/* Check whether the MSI feature has been enabled by the PCI host. */
|
||||
|
|
@ -482,16 +488,16 @@ static int cdns_pcie_ep_map_msi_irq(struct pci_epc *epc, u8 fn, u8 vfn,
|
|||
static int cdns_pcie_ep_send_msix_irq(struct cdns_pcie_ep *ep, u8 fn, u8 vfn,
|
||||
u16 interrupt_num)
|
||||
{
|
||||
u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
|
||||
u32 tbl_offset, msg_data, reg;
|
||||
struct cdns_pcie *pcie = &ep->pcie;
|
||||
struct pci_epf_msix_tbl *msix_tbl;
|
||||
struct cdns_pcie_epf *epf;
|
||||
u64 pci_addr_mask = 0xff;
|
||||
u64 msg_addr;
|
||||
u8 bir, cap;
|
||||
u16 flags;
|
||||
u8 bir;
|
||||
|
||||
cap = cdns_pcie_find_capability(pcie, PCI_CAP_ID_MSIX);
|
||||
epf = &ep->epf[fn];
|
||||
if (vfn > 0)
|
||||
epf = &epf->epf[vfn - 1];
|
||||
|
|
@ -565,7 +571,9 @@ static int cdns_pcie_ep_start(struct pci_epc *epc)
|
|||
int max_epfs = sizeof(epc->function_num_map) * 8;
|
||||
int ret, epf, last_fn;
|
||||
u32 reg, value;
|
||||
u8 cap;
|
||||
|
||||
cap = cdns_pcie_find_capability(pcie, PCI_CAP_ID_EXP);
|
||||
/*
|
||||
* BIT(0) is hardwired to 1, hence function 0 is always enabled
|
||||
* and can't be disabled anyway.
|
||||
|
|
@ -589,12 +597,10 @@ static int cdns_pcie_ep_start(struct pci_epc *epc)
|
|||
continue;
|
||||
|
||||
value = cdns_pcie_ep_fn_readl(pcie, epf,
|
||||
CDNS_PCIE_EP_FUNC_DEV_CAP_OFFSET +
|
||||
PCI_EXP_DEVCAP);
|
||||
cap + PCI_EXP_DEVCAP);
|
||||
value &= ~PCI_EXP_DEVCAP_FLR;
|
||||
cdns_pcie_ep_fn_writel(pcie, epf,
|
||||
CDNS_PCIE_EP_FUNC_DEV_CAP_OFFSET +
|
||||
PCI_EXP_DEVCAP, value);
|
||||
cap + PCI_EXP_DEVCAP, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,20 @@
|
|||
#include <linux/of.h>
|
||||
|
||||
#include "pcie-cadence.h"
|
||||
#include "../../pci.h"
|
||||
|
||||
u8 cdns_pcie_find_capability(struct cdns_pcie *pcie, u8 cap)
|
||||
{
|
||||
return PCI_FIND_NEXT_CAP(cdns_pcie_read_cfg, PCI_CAPABILITY_LIST,
|
||||
cap, pcie);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cdns_pcie_find_capability);
|
||||
|
||||
u16 cdns_pcie_find_ext_capability(struct cdns_pcie *pcie, u8 cap)
|
||||
{
|
||||
return PCI_FIND_NEXT_EXT_CAP(cdns_pcie_read_cfg, 0, cap, pcie);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cdns_pcie_find_ext_capability);
|
||||
|
||||
void cdns_pcie_detect_quiet_min_delay_set(struct cdns_pcie *pcie)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -125,11 +125,6 @@
|
|||
*/
|
||||
#define CDNS_PCIE_EP_FUNC_BASE(fn) (((fn) << 12) & GENMASK(19, 12))
|
||||
|
||||
#define CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET 0x90
|
||||
#define CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET 0xb0
|
||||
#define CDNS_PCIE_EP_FUNC_DEV_CAP_OFFSET 0xc0
|
||||
#define CDNS_PCIE_EP_FUNC_SRIOV_CAP_OFFSET 0x200
|
||||
|
||||
/*
|
||||
* Endpoint PF Registers
|
||||
*/
|
||||
|
|
@ -367,6 +362,37 @@ static inline u32 cdns_pcie_readl(struct cdns_pcie *pcie, u32 reg)
|
|||
return readl(pcie->reg_base + reg);
|
||||
}
|
||||
|
||||
static inline u16 cdns_pcie_readw(struct cdns_pcie *pcie, u32 reg)
|
||||
{
|
||||
return readw(pcie->reg_base + reg);
|
||||
}
|
||||
|
||||
static inline u8 cdns_pcie_readb(struct cdns_pcie *pcie, u32 reg)
|
||||
{
|
||||
return readb(pcie->reg_base + reg);
|
||||
}
|
||||
|
||||
static inline int cdns_pcie_read_cfg_byte(struct cdns_pcie *pcie, int where,
|
||||
u8 *val)
|
||||
{
|
||||
*val = cdns_pcie_readb(pcie, where);
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static inline int cdns_pcie_read_cfg_word(struct cdns_pcie *pcie, int where,
|
||||
u16 *val)
|
||||
{
|
||||
*val = cdns_pcie_readw(pcie, where);
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static inline int cdns_pcie_read_cfg_dword(struct cdns_pcie *pcie, int where,
|
||||
u32 *val)
|
||||
{
|
||||
*val = cdns_pcie_readl(pcie, where);
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static inline u32 cdns_pcie_read_sz(void __iomem *addr, int size)
|
||||
{
|
||||
void __iomem *aligned_addr = PTR_ALIGN_DOWN(addr, 0x4);
|
||||
|
|
@ -536,6 +562,9 @@ static inline void cdns_pcie_ep_disable(struct cdns_pcie_ep *ep)
|
|||
}
|
||||
#endif
|
||||
|
||||
u8 cdns_pcie_find_capability(struct cdns_pcie *pcie, u8 cap);
|
||||
u16 cdns_pcie_find_ext_capability(struct cdns_pcie *pcie, u8 cap);
|
||||
|
||||
void cdns_pcie_detect_quiet_min_delay_set(struct cdns_pcie *pcie);
|
||||
|
||||
void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 busnr, u8 fn,
|
||||
|
|
|
|||
|
|
@ -69,37 +69,10 @@ void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_ep_reset_bar);
|
||||
|
||||
static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie_ep *ep, u8 func_no,
|
||||
u8 cap_ptr, u8 cap)
|
||||
{
|
||||
u8 cap_id, next_cap_ptr;
|
||||
u16 reg;
|
||||
|
||||
if (!cap_ptr)
|
||||
return 0;
|
||||
|
||||
reg = dw_pcie_ep_readw_dbi(ep, func_no, cap_ptr);
|
||||
cap_id = (reg & 0x00ff);
|
||||
|
||||
if (cap_id > PCI_CAP_ID_MAX)
|
||||
return 0;
|
||||
|
||||
if (cap_id == cap)
|
||||
return cap_ptr;
|
||||
|
||||
next_cap_ptr = (reg & 0xff00) >> 8;
|
||||
return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap);
|
||||
}
|
||||
|
||||
static u8 dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, u8 func_no, u8 cap)
|
||||
{
|
||||
u8 next_cap_ptr;
|
||||
u16 reg;
|
||||
|
||||
reg = dw_pcie_ep_readw_dbi(ep, func_no, PCI_CAPABILITY_LIST);
|
||||
next_cap_ptr = (reg & 0x00ff);
|
||||
|
||||
return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap);
|
||||
return PCI_FIND_NEXT_CAP(dw_pcie_ep_read_cfg, PCI_CAPABILITY_LIST,
|
||||
cap, ep, func_no);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -213,83 +213,16 @@ void dw_pcie_version_detect(struct dw_pcie *pci)
|
|||
pci->type = ver;
|
||||
}
|
||||
|
||||
/*
|
||||
* These interfaces resemble the pci_find_*capability() interfaces, but these
|
||||
* are for configuring host controllers, which are bridges *to* PCI devices but
|
||||
* are not PCI devices themselves.
|
||||
*/
|
||||
static u8 __dw_pcie_find_next_cap(struct dw_pcie *pci, u8 cap_ptr,
|
||||
u8 cap)
|
||||
{
|
||||
u8 cap_id, next_cap_ptr;
|
||||
u16 reg;
|
||||
|
||||
if (!cap_ptr)
|
||||
return 0;
|
||||
|
||||
reg = dw_pcie_readw_dbi(pci, cap_ptr);
|
||||
cap_id = (reg & 0x00ff);
|
||||
|
||||
if (cap_id > PCI_CAP_ID_MAX)
|
||||
return 0;
|
||||
|
||||
if (cap_id == cap)
|
||||
return cap_ptr;
|
||||
|
||||
next_cap_ptr = (reg & 0xff00) >> 8;
|
||||
return __dw_pcie_find_next_cap(pci, next_cap_ptr, cap);
|
||||
}
|
||||
|
||||
u8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap)
|
||||
{
|
||||
u8 next_cap_ptr;
|
||||
u16 reg;
|
||||
|
||||
reg = dw_pcie_readw_dbi(pci, PCI_CAPABILITY_LIST);
|
||||
next_cap_ptr = (reg & 0x00ff);
|
||||
|
||||
return __dw_pcie_find_next_cap(pci, next_cap_ptr, cap);
|
||||
return PCI_FIND_NEXT_CAP(dw_pcie_read_cfg, PCI_CAPABILITY_LIST, cap,
|
||||
pci);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_find_capability);
|
||||
|
||||
static u16 dw_pcie_find_next_ext_capability(struct dw_pcie *pci, u16 start,
|
||||
u8 cap)
|
||||
{
|
||||
u32 header;
|
||||
int ttl;
|
||||
int pos = PCI_CFG_SPACE_SIZE;
|
||||
|
||||
/* minimum 8 bytes per capability */
|
||||
ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
|
||||
|
||||
if (start)
|
||||
pos = start;
|
||||
|
||||
header = dw_pcie_readl_dbi(pci, pos);
|
||||
/*
|
||||
* If we have no capabilities, this is indicated by cap ID,
|
||||
* cap version and next pointer all being 0.
|
||||
*/
|
||||
if (header == 0)
|
||||
return 0;
|
||||
|
||||
while (ttl-- > 0) {
|
||||
if (PCI_EXT_CAP_ID(header) == cap && pos != start)
|
||||
return pos;
|
||||
|
||||
pos = PCI_EXT_CAP_NEXT(header);
|
||||
if (pos < PCI_CFG_SPACE_SIZE)
|
||||
break;
|
||||
|
||||
header = dw_pcie_readl_dbi(pci, pos);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap)
|
||||
{
|
||||
return dw_pcie_find_next_ext_capability(pci, 0, cap);
|
||||
return PCI_FIND_NEXT_EXT_CAP(dw_pcie_read_cfg, 0, cap, pci);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_find_ext_capability);
|
||||
|
||||
|
|
@ -302,8 +235,8 @@ static u16 __dw_pcie_find_vsec_capability(struct dw_pcie *pci, u16 vendor_id,
|
|||
if (vendor_id != dw_pcie_readw_dbi(pci, PCI_VENDOR_ID))
|
||||
return 0;
|
||||
|
||||
while ((vsec = dw_pcie_find_next_ext_capability(pci, vsec,
|
||||
PCI_EXT_CAP_ID_VNDR))) {
|
||||
while ((vsec = PCI_FIND_NEXT_EXT_CAP(dw_pcie_read_cfg, vsec,
|
||||
PCI_EXT_CAP_ID_VNDR, pci))) {
|
||||
header = dw_pcie_readl_dbi(pci, vsec + PCI_VNDR_HEADER);
|
||||
if (PCI_VNDR_HEADER_ID(header) == vsec_id)
|
||||
return vsec;
|
||||
|
|
|
|||
|
|
@ -609,6 +609,27 @@ static inline void dw_pcie_writel_dbi2(struct dw_pcie *pci, u32 reg, u32 val)
|
|||
dw_pcie_write_dbi2(pci, reg, 0x4, val);
|
||||
}
|
||||
|
||||
static inline int dw_pcie_read_cfg_byte(struct dw_pcie *pci, int where,
|
||||
u8 *val)
|
||||
{
|
||||
*val = dw_pcie_readb_dbi(pci, where);
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static inline int dw_pcie_read_cfg_word(struct dw_pcie *pci, int where,
|
||||
u16 *val)
|
||||
{
|
||||
*val = dw_pcie_readw_dbi(pci, where);
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static inline int dw_pcie_read_cfg_dword(struct dw_pcie *pci, int where,
|
||||
u32 *val)
|
||||
{
|
||||
*val = dw_pcie_readl_dbi(pci, where);
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static inline unsigned int dw_pcie_ep_get_dbi_offset(struct dw_pcie_ep *ep,
|
||||
u8 func_no)
|
||||
{
|
||||
|
|
@ -674,6 +695,27 @@ static inline u8 dw_pcie_ep_readb_dbi(struct dw_pcie_ep *ep, u8 func_no,
|
|||
return dw_pcie_ep_read_dbi(ep, func_no, reg, 0x1);
|
||||
}
|
||||
|
||||
static inline int dw_pcie_ep_read_cfg_byte(struct dw_pcie_ep *ep, u8 func_no,
|
||||
int where, u8 *val)
|
||||
{
|
||||
*val = dw_pcie_ep_readb_dbi(ep, func_no, where);
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static inline int dw_pcie_ep_read_cfg_word(struct dw_pcie_ep *ep, u8 func_no,
|
||||
int where, u16 *val)
|
||||
{
|
||||
*val = dw_pcie_ep_readw_dbi(ep, func_no, where);
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static inline int dw_pcie_ep_read_cfg_dword(struct dw_pcie_ep *ep, u8 func_no,
|
||||
int where, u32 *val)
|
||||
{
|
||||
*val = dw_pcie_ep_readl_dbi(ep, func_no, where);
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static inline unsigned int dw_pcie_ep_get_dbi2_offset(struct dw_pcie_ep *ep,
|
||||
u8 func_no)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -423,36 +423,10 @@ static int pci_dev_str_match(struct pci_dev *dev, const char *p,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static u8 __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn,
|
||||
u8 pos, int cap, int *ttl)
|
||||
{
|
||||
u8 id;
|
||||
u16 ent;
|
||||
|
||||
pci_bus_read_config_byte(bus, devfn, pos, &pos);
|
||||
|
||||
while ((*ttl)--) {
|
||||
if (pos < 0x40)
|
||||
break;
|
||||
pos &= ~3;
|
||||
pci_bus_read_config_word(bus, devfn, pos, &ent);
|
||||
|
||||
id = ent & 0xff;
|
||||
if (id == 0xff)
|
||||
break;
|
||||
if (id == cap)
|
||||
return pos;
|
||||
pos = (ent >> 8);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn,
|
||||
u8 pos, int cap)
|
||||
{
|
||||
int ttl = PCI_FIND_CAP_TTL;
|
||||
|
||||
return __pci_find_next_cap_ttl(bus, devfn, pos, cap, &ttl);
|
||||
return PCI_FIND_NEXT_CAP(pci_bus_read_config, pos, cap, bus, devfn);
|
||||
}
|
||||
|
||||
u8 pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap)
|
||||
|
|
@ -553,42 +527,11 @@ EXPORT_SYMBOL(pci_bus_find_capability);
|
|||
*/
|
||||
u16 pci_find_next_ext_capability(struct pci_dev *dev, u16 start, int cap)
|
||||
{
|
||||
u32 header;
|
||||
int ttl;
|
||||
u16 pos = PCI_CFG_SPACE_SIZE;
|
||||
|
||||
/* minimum 8 bytes per capability */
|
||||
ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
|
||||
|
||||
if (dev->cfg_size <= PCI_CFG_SPACE_SIZE)
|
||||
return 0;
|
||||
|
||||
if (start)
|
||||
pos = start;
|
||||
|
||||
if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If we have no capabilities, this is indicated by cap ID,
|
||||
* cap version and next pointer all being 0.
|
||||
*/
|
||||
if (header == 0)
|
||||
return 0;
|
||||
|
||||
while (ttl-- > 0) {
|
||||
if (PCI_EXT_CAP_ID(header) == cap && pos != start)
|
||||
return pos;
|
||||
|
||||
pos = PCI_EXT_CAP_NEXT(header);
|
||||
if (pos < PCI_CFG_SPACE_SIZE)
|
||||
break;
|
||||
|
||||
if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return PCI_FIND_NEXT_EXT_CAP(pci_bus_read_config, start, cap,
|
||||
dev->bus, dev->devfn);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_find_next_ext_capability);
|
||||
|
||||
|
|
@ -648,7 +591,7 @@ EXPORT_SYMBOL_GPL(pci_get_dsn);
|
|||
|
||||
static u8 __pci_find_next_ht_cap(struct pci_dev *dev, u8 pos, int ht_cap)
|
||||
{
|
||||
int rc, ttl = PCI_FIND_CAP_TTL;
|
||||
int rc;
|
||||
u8 cap, mask;
|
||||
|
||||
if (ht_cap == HT_CAPTYPE_SLAVE || ht_cap == HT_CAPTYPE_HOST)
|
||||
|
|
@ -656,8 +599,8 @@ static u8 __pci_find_next_ht_cap(struct pci_dev *dev, u8 pos, int ht_cap)
|
|||
else
|
||||
mask = HT_5BIT_CAP_MASK;
|
||||
|
||||
pos = __pci_find_next_cap_ttl(dev->bus, dev->devfn, pos,
|
||||
PCI_CAP_ID_HT, &ttl);
|
||||
pos = PCI_FIND_NEXT_CAP(pci_bus_read_config, pos,
|
||||
PCI_CAP_ID_HT, dev->bus, dev->devfn);
|
||||
while (pos) {
|
||||
rc = pci_read_config_byte(dev, pos + 3, &cap);
|
||||
if (rc != PCIBIOS_SUCCESSFUL)
|
||||
|
|
@ -666,9 +609,10 @@ static u8 __pci_find_next_ht_cap(struct pci_dev *dev, u8 pos, int ht_cap)
|
|||
if ((cap & mask) == ht_cap)
|
||||
return pos;
|
||||
|
||||
pos = __pci_find_next_cap_ttl(dev->bus, dev->devfn,
|
||||
pos + PCI_CAP_LIST_NEXT,
|
||||
PCI_CAP_ID_HT, &ttl);
|
||||
pos = PCI_FIND_NEXT_CAP(pci_bus_read_config,
|
||||
pos + PCI_CAP_LIST_NEXT,
|
||||
PCI_CAP_ID_HT, dev->bus,
|
||||
dev->devfn);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
#ifndef DRIVERS_PCI_H
|
||||
#define DRIVERS_PCI_H
|
||||
|
||||
#include <linux/align.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
struct pcie_tlp_log;
|
||||
|
|
@ -95,6 +97,89 @@ bool pcie_cap_has_lnkctl(const struct pci_dev *dev);
|
|||
bool pcie_cap_has_lnkctl2(const struct pci_dev *dev);
|
||||
bool pcie_cap_has_rtctl(const struct pci_dev *dev);
|
||||
|
||||
/* Standard Capability finder */
|
||||
/**
|
||||
* PCI_FIND_NEXT_CAP - Find a PCI standard capability
|
||||
* @read_cfg: Function pointer for reading PCI config space
|
||||
* @start: Starting position to begin search
|
||||
* @cap: Capability ID to find
|
||||
* @args: Arguments to pass to read_cfg function
|
||||
*
|
||||
* Search the capability list in PCI config space to find @cap.
|
||||
* Implements TTL (time-to-live) protection against infinite loops.
|
||||
*
|
||||
* Return: Position of the capability if found, 0 otherwise.
|
||||
*/
|
||||
#define PCI_FIND_NEXT_CAP(read_cfg, start, cap, args...) \
|
||||
({ \
|
||||
int __ttl = PCI_FIND_CAP_TTL; \
|
||||
u8 __id, __found_pos = 0; \
|
||||
u8 __pos = (start); \
|
||||
u16 __ent; \
|
||||
\
|
||||
read_cfg##_byte(args, __pos, &__pos); \
|
||||
\
|
||||
while (__ttl--) { \
|
||||
if (__pos < PCI_STD_HEADER_SIZEOF) \
|
||||
break; \
|
||||
\
|
||||
__pos = ALIGN_DOWN(__pos, 4); \
|
||||
read_cfg##_word(args, __pos, &__ent); \
|
||||
\
|
||||
__id = FIELD_GET(PCI_CAP_ID_MASK, __ent); \
|
||||
if (__id == 0xff) \
|
||||
break; \
|
||||
\
|
||||
if (__id == (cap)) { \
|
||||
__found_pos = __pos; \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
__pos = FIELD_GET(PCI_CAP_LIST_NEXT_MASK, __ent); \
|
||||
} \
|
||||
__found_pos; \
|
||||
})
|
||||
|
||||
/* Extended Capability finder */
|
||||
/**
|
||||
* PCI_FIND_NEXT_EXT_CAP - Find a PCI extended capability
|
||||
* @read_cfg: Function pointer for reading PCI config space
|
||||
* @start: Starting position to begin search (0 for initial search)
|
||||
* @cap: Extended capability ID to find
|
||||
* @args: Arguments to pass to read_cfg function
|
||||
*
|
||||
* Search the extended capability list in PCI config space to find @cap.
|
||||
* Implements TTL protection against infinite loops using a calculated
|
||||
* maximum search count.
|
||||
*
|
||||
* Return: Position of the capability if found, 0 otherwise.
|
||||
*/
|
||||
#define PCI_FIND_NEXT_EXT_CAP(read_cfg, start, cap, args...) \
|
||||
({ \
|
||||
u16 __pos = (start) ?: PCI_CFG_SPACE_SIZE; \
|
||||
u16 __found_pos = 0; \
|
||||
int __ttl, __ret; \
|
||||
u32 __header; \
|
||||
\
|
||||
__ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8; \
|
||||
while (__ttl-- > 0 && __pos >= PCI_CFG_SPACE_SIZE) { \
|
||||
__ret = read_cfg##_dword(args, __pos, &__header); \
|
||||
if (__ret != PCIBIOS_SUCCESSFUL) \
|
||||
break; \
|
||||
\
|
||||
if (__header == 0) \
|
||||
break; \
|
||||
\
|
||||
if (PCI_EXT_CAP_ID(__header) == (cap) && __pos != start) {\
|
||||
__found_pos = __pos; \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
__pos = PCI_EXT_CAP_NEXT(__header); \
|
||||
} \
|
||||
__found_pos; \
|
||||
})
|
||||
|
||||
/* Functions internal to the PCI core code */
|
||||
|
||||
#ifdef CONFIG_DMI
|
||||
|
|
|
|||
|
|
@ -207,6 +207,9 @@
|
|||
|
||||
/* Capability lists */
|
||||
|
||||
#define PCI_CAP_ID_MASK 0x00ff /* Capability ID mask */
|
||||
#define PCI_CAP_LIST_NEXT_MASK 0xff00 /* Next Capability Pointer mask */
|
||||
|
||||
#define PCI_CAP_LIST_ID 0 /* Capability ID */
|
||||
#define PCI_CAP_ID_PM 0x01 /* Power Management */
|
||||
#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user