mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-23 04:34:11 +08:00
Merge branch 'remotes/lorenzo/pci/endpoint'
- Use memcpy_fromio()/memcpy_toio() instead of plain memcpy() in PCI endpoint framework (Wen Yang) - Add interface to discover supported endpoint features to replace a bitfield that wasn't flexible enough (Kishon Vijay Abraham I) - Implement the new supported-feature interface for designware-plat, dra7xx, rockchip, cadence (Kishon Vijay Abraham I) - Fix issues with 64-bit BAR in endpoints (Kishon Vijay Abraham I) - Add layerscape endpoint mode support (Xiaowei Bao) * remotes/lorenzo/pci/endpoint: misc: pci_endpoint_test: Add the layerscape EP device support PCI: layerscape: Add EP mode support arm64: dts: Add the PCIE EP node in dts dt-bindings: add DT binding for the layerscape PCIe controller with EP mode PCI: endpoint: Remove features member in struct pci_epc PCI: designware-plat: Remove setting epc->features in Designware plat EP driver PCI: rockchip: Remove pci_epf_linkup() from Rockchip EP driver PCI: cadence: Remove pci_epf_linkup() from Cadence EP driver PCI: pci-epf-test: Use pci_epc_get_features() to get EPC features PCI: pci-epf-test: Do not allocate next BARs memory if current BAR is 64Bit PCI: pci-epf-test: Remove setting epf_bar flags in function driver PCI: endpoint: Fix pci_epf_alloc_space() to set correct MEM TYPE flags PCI: endpoint: Add helper to get first unreserved BAR PCI: cadence: Populate ->get_features() cdns_pcie_epc_ops PCI: rockchip: Populate ->get_features() dw_pcie_ep_ops PCI: pci-dra7xx: Populate ->get_features() dw_pcie_ep_ops PCI: designware-plat: Populate ->get_features() dw_pcie_ep_ops PCI: dwc: Add ->get_features() callback function to dw_pcie_ep_ops PCI: endpoint: Add new pci_epc_ops to get EPC features PCI: endpoint: functions: Use memcpy_fromio()/memcpy_toio()
This commit is contained in:
commit
7e5b22ddb2
@ -13,6 +13,7 @@ information.
|
|||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
- compatible: should contain the platform identifier such as:
|
- compatible: should contain the platform identifier such as:
|
||||||
|
RC mode:
|
||||||
"fsl,ls1021a-pcie"
|
"fsl,ls1021a-pcie"
|
||||||
"fsl,ls2080a-pcie", "fsl,ls2085a-pcie"
|
"fsl,ls2080a-pcie", "fsl,ls2085a-pcie"
|
||||||
"fsl,ls2088a-pcie"
|
"fsl,ls2088a-pcie"
|
||||||
@ -20,6 +21,8 @@ Required properties:
|
|||||||
"fsl,ls1046a-pcie"
|
"fsl,ls1046a-pcie"
|
||||||
"fsl,ls1043a-pcie"
|
"fsl,ls1043a-pcie"
|
||||||
"fsl,ls1012a-pcie"
|
"fsl,ls1012a-pcie"
|
||||||
|
EP mode:
|
||||||
|
"fsl,ls1046a-pcie-ep", "fsl,ls-pcie-ep"
|
||||||
- reg: base addresses and lengths of the PCIe controller register blocks.
|
- reg: base addresses and lengths of the PCIe controller register blocks.
|
||||||
- interrupts: A list of interrupt outputs of the controller. Must contain an
|
- interrupts: A list of interrupt outputs of the controller. Must contain an
|
||||||
entry for each entry in the interrupt-names property.
|
entry for each entry in the interrupt-names property.
|
||||||
|
@ -657,6 +657,17 @@
|
|||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pcie_ep@3400000 {
|
||||||
|
compatible = "fsl,ls1046a-pcie-ep","fsl,ls-pcie-ep";
|
||||||
|
reg = <0x00 0x03400000 0x0 0x00100000
|
||||||
|
0x40 0x00000000 0x8 0x00000000>;
|
||||||
|
reg-names = "regs", "addr_space";
|
||||||
|
num-ib-windows = <6>;
|
||||||
|
num-ob-windows = <8>;
|
||||||
|
num-lanes = <2>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
pcie@3500000 {
|
pcie@3500000 {
|
||||||
compatible = "fsl,ls1046a-pcie";
|
compatible = "fsl,ls1046a-pcie";
|
||||||
reg = <0x00 0x03500000 0x0 0x00100000 /* controller registers */
|
reg = <0x00 0x03500000 0x0 0x00100000 /* controller registers */
|
||||||
@ -683,6 +694,17 @@
|
|||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pcie_ep@3500000 {
|
||||||
|
compatible = "fsl,ls1046a-pcie-ep","fsl,ls-pcie-ep";
|
||||||
|
reg = <0x00 0x03500000 0x0 0x00100000
|
||||||
|
0x48 0x00000000 0x8 0x00000000>;
|
||||||
|
reg-names = "regs", "addr_space";
|
||||||
|
num-ib-windows = <6>;
|
||||||
|
num-ob-windows = <8>;
|
||||||
|
num-lanes = <2>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
pcie@3600000 {
|
pcie@3600000 {
|
||||||
compatible = "fsl,ls1046a-pcie";
|
compatible = "fsl,ls1046a-pcie";
|
||||||
reg = <0x00 0x03600000 0x0 0x00100000 /* controller registers */
|
reg = <0x00 0x03600000 0x0 0x00100000 /* controller registers */
|
||||||
@ -709,6 +731,17 @@
|
|||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pcie_ep@3600000 {
|
||||||
|
compatible = "fsl,ls1046a-pcie-ep", "fsl,ls-pcie-ep";
|
||||||
|
reg = <0x00 0x03600000 0x0 0x00100000
|
||||||
|
0x50 0x00000000 0x8 0x00000000>;
|
||||||
|
reg-names = "regs", "addr_space";
|
||||||
|
num-ib-windows = <6>;
|
||||||
|
num-ob-windows = <8>;
|
||||||
|
num-lanes = <2>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
qdma: dma-controller@8380000 {
|
qdma: dma-controller@8380000 {
|
||||||
compatible = "fsl,ls1046a-qdma", "fsl,ls1021a-qdma";
|
compatible = "fsl,ls1046a-qdma", "fsl,ls1021a-qdma";
|
||||||
reg = <0x0 0x8380000 0x0 0x1000>, /* Controller regs */
|
reg = <0x0 0x8380000 0x0 0x1000>, /* Controller regs */
|
||||||
@ -729,7 +762,6 @@
|
|||||||
queue-sizes = <64 64>;
|
queue-sizes = <64 64>;
|
||||||
big-endian;
|
big-endian;
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
reserved-memory {
|
reserved-memory {
|
||||||
|
@ -788,6 +788,7 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev)
|
|||||||
static const struct pci_device_id pci_endpoint_test_tbl[] = {
|
static const struct pci_device_id pci_endpoint_test_tbl[] = {
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x) },
|
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x) },
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x) },
|
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x) },
|
||||||
|
{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0) },
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, 0xedda) },
|
{ PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, 0xedda) },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
@ -8,7 +8,7 @@ obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
|
|||||||
obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
|
obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
|
||||||
obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
|
obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
|
||||||
obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone.o
|
obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone.o
|
||||||
obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o
|
obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o pci-layerscape-ep.o
|
||||||
obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o
|
obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o
|
||||||
obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o
|
obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o
|
||||||
obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o
|
obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o
|
||||||
|
@ -394,9 +394,22 @@ static int dra7xx_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct pci_epc_features dra7xx_pcie_epc_features = {
|
||||||
|
.linkup_notifier = true,
|
||||||
|
.msi_capable = true,
|
||||||
|
.msix_capable = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct pci_epc_features*
|
||||||
|
dra7xx_pcie_get_features(struct dw_pcie_ep *ep)
|
||||||
|
{
|
||||||
|
return &dra7xx_pcie_epc_features;
|
||||||
|
}
|
||||||
|
|
||||||
static struct dw_pcie_ep_ops pcie_ep_ops = {
|
static struct dw_pcie_ep_ops pcie_ep_ops = {
|
||||||
.ep_init = dra7xx_pcie_ep_init,
|
.ep_init = dra7xx_pcie_ep_init,
|
||||||
.raise_irq = dra7xx_pcie_raise_irq,
|
.raise_irq = dra7xx_pcie_raise_irq,
|
||||||
|
.get_features = dra7xx_pcie_get_features,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx,
|
static int __init dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx,
|
||||||
|
156
drivers/pci/controller/dwc/pci-layerscape-ep.c
Normal file
156
drivers/pci/controller/dwc/pci-layerscape-ep.c
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* PCIe controller EP driver for Freescale Layerscape SoCs
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 NXP Semiconductor.
|
||||||
|
*
|
||||||
|
* Author: Xiaowei Bao <xiaowei.bao@nxp.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/of_pci.h>
|
||||||
|
#include <linux/of_platform.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/pci.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/resource.h>
|
||||||
|
|
||||||
|
#include "pcie-designware.h"
|
||||||
|
|
||||||
|
#define PCIE_DBI2_OFFSET 0x1000 /* DBI2 base address*/
|
||||||
|
|
||||||
|
struct ls_pcie_ep {
|
||||||
|
struct dw_pcie *pci;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev)
|
||||||
|
|
||||||
|
static int ls_pcie_establish_link(struct dw_pcie *pci)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct dw_pcie_ops ls_pcie_ep_ops = {
|
||||||
|
.start_link = ls_pcie_establish_link,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id ls_pcie_ep_of_match[] = {
|
||||||
|
{ .compatible = "fsl,ls-pcie-ep",},
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct pci_epc_features ls_pcie_epc_features = {
|
||||||
|
.linkup_notifier = false,
|
||||||
|
.msi_capable = true,
|
||||||
|
.msix_capable = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct pci_epc_features*
|
||||||
|
ls_pcie_ep_get_features(struct dw_pcie_ep *ep)
|
||||||
|
{
|
||||||
|
return &ls_pcie_epc_features;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ls_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||||
|
{
|
||||||
|
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||||
|
enum pci_barno bar;
|
||||||
|
|
||||||
|
for (bar = BAR_0; bar <= BAR_5; bar++)
|
||||||
|
dw_pcie_ep_reset_bar(pci, bar);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||||
|
enum pci_epc_irq_type type, u16 interrupt_num)
|
||||||
|
{
|
||||||
|
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case PCI_EPC_IRQ_LEGACY:
|
||||||
|
return dw_pcie_ep_raise_legacy_irq(ep, func_no);
|
||||||
|
case PCI_EPC_IRQ_MSI:
|
||||||
|
return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
|
||||||
|
case PCI_EPC_IRQ_MSIX:
|
||||||
|
return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num);
|
||||||
|
default:
|
||||||
|
dev_err(pci->dev, "UNKNOWN IRQ type\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct dw_pcie_ep_ops pcie_ep_ops = {
|
||||||
|
.ep_init = ls_pcie_ep_init,
|
||||||
|
.raise_irq = ls_pcie_ep_raise_irq,
|
||||||
|
.get_features = ls_pcie_ep_get_features,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init ls_add_pcie_ep(struct ls_pcie_ep *pcie,
|
||||||
|
struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct dw_pcie *pci = pcie->pci;
|
||||||
|
struct device *dev = pci->dev;
|
||||||
|
struct dw_pcie_ep *ep;
|
||||||
|
struct resource *res;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ep = &pci->ep;
|
||||||
|
ep->ops = &pcie_ep_ops;
|
||||||
|
|
||||||
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
|
||||||
|
if (!res)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
ep->phys_base = res->start;
|
||||||
|
ep->addr_size = resource_size(res);
|
||||||
|
|
||||||
|
ret = dw_pcie_ep_init(ep);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "failed to initialize endpoint\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init ls_pcie_ep_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct dw_pcie *pci;
|
||||||
|
struct ls_pcie_ep *pcie;
|
||||||
|
struct resource *dbi_base;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
|
||||||
|
if (!pcie)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
|
||||||
|
if (!pci)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
|
||||||
|
pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base);
|
||||||
|
if (IS_ERR(pci->dbi_base))
|
||||||
|
return PTR_ERR(pci->dbi_base);
|
||||||
|
|
||||||
|
pci->dbi_base2 = pci->dbi_base + PCIE_DBI2_OFFSET;
|
||||||
|
pci->dev = dev;
|
||||||
|
pci->ops = &ls_pcie_ep_ops;
|
||||||
|
pcie->pci = pci;
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, pcie);
|
||||||
|
|
||||||
|
ret = ls_add_pcie_ep(pcie, pdev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver ls_pcie_ep_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "layerscape-pcie-ep",
|
||||||
|
.of_match_table = ls_pcie_ep_of_match,
|
||||||
|
.suppress_bind_attrs = true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
builtin_platform_driver_probe(ls_pcie_ep_driver, ls_pcie_ep_probe);
|
@ -355,6 +355,17 @@ static int dw_pcie_ep_start(struct pci_epc *epc)
|
|||||||
return pci->ops->start_link(pci);
|
return pci->ops->start_link(pci);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct pci_epc_features*
|
||||||
|
dw_pcie_ep_get_features(struct pci_epc *epc, u8 func_no)
|
||||||
|
{
|
||||||
|
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
|
||||||
|
|
||||||
|
if (!ep->ops->get_features)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return ep->ops->get_features(ep);
|
||||||
|
}
|
||||||
|
|
||||||
static const struct pci_epc_ops epc_ops = {
|
static const struct pci_epc_ops epc_ops = {
|
||||||
.write_header = dw_pcie_ep_write_header,
|
.write_header = dw_pcie_ep_write_header,
|
||||||
.set_bar = dw_pcie_ep_set_bar,
|
.set_bar = dw_pcie_ep_set_bar,
|
||||||
@ -368,6 +379,7 @@ static const struct pci_epc_ops epc_ops = {
|
|||||||
.raise_irq = dw_pcie_ep_raise_irq,
|
.raise_irq = dw_pcie_ep_raise_irq,
|
||||||
.start = dw_pcie_ep_start,
|
.start = dw_pcie_ep_start,
|
||||||
.stop = dw_pcie_ep_stop,
|
.stop = dw_pcie_ep_stop,
|
||||||
|
.get_features = dw_pcie_ep_get_features,
|
||||||
};
|
};
|
||||||
|
|
||||||
int dw_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep, u8 func_no)
|
int dw_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep, u8 func_no)
|
||||||
|
@ -68,14 +68,10 @@ static const struct dw_pcie_ops dw_pcie_ops = {
|
|||||||
static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep)
|
static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||||
{
|
{
|
||||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||||
struct pci_epc *epc = ep->epc;
|
|
||||||
enum pci_barno bar;
|
enum pci_barno bar;
|
||||||
|
|
||||||
for (bar = BAR_0; bar <= BAR_5; bar++)
|
for (bar = BAR_0; bar <= BAR_5; bar++)
|
||||||
dw_pcie_ep_reset_bar(pci, bar);
|
dw_pcie_ep_reset_bar(pci, bar);
|
||||||
|
|
||||||
epc->features |= EPC_FEATURE_NO_LINKUP_NOTIFIER;
|
|
||||||
epc->features |= EPC_FEATURE_MSIX_AVAILABLE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
|
static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||||
@ -98,9 +94,22 @@ static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct pci_epc_features dw_plat_pcie_epc_features = {
|
||||||
|
.linkup_notifier = false,
|
||||||
|
.msi_capable = true,
|
||||||
|
.msix_capable = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct pci_epc_features*
|
||||||
|
dw_plat_pcie_get_features(struct dw_pcie_ep *ep)
|
||||||
|
{
|
||||||
|
return &dw_plat_pcie_epc_features;
|
||||||
|
}
|
||||||
|
|
||||||
static struct dw_pcie_ep_ops pcie_ep_ops = {
|
static struct dw_pcie_ep_ops pcie_ep_ops = {
|
||||||
.ep_init = dw_plat_pcie_ep_init,
|
.ep_init = dw_plat_pcie_ep_init,
|
||||||
.raise_irq = dw_plat_pcie_ep_raise_irq,
|
.raise_irq = dw_plat_pcie_ep_raise_irq,
|
||||||
|
.get_features = dw_plat_pcie_get_features,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie,
|
static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie,
|
||||||
|
@ -195,6 +195,7 @@ struct dw_pcie_ep_ops {
|
|||||||
void (*ep_init)(struct dw_pcie_ep *ep);
|
void (*ep_init)(struct dw_pcie_ep *ep);
|
||||||
int (*raise_irq)(struct dw_pcie_ep *ep, u8 func_no,
|
int (*raise_irq)(struct dw_pcie_ep *ep, u8 func_no,
|
||||||
enum pci_epc_irq_type type, u16 interrupt_num);
|
enum pci_epc_irq_type type, u16 interrupt_num);
|
||||||
|
const struct pci_epc_features* (*get_features)(struct dw_pcie_ep *ep);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dw_pcie_ep {
|
struct dw_pcie_ep {
|
||||||
|
@ -396,21 +396,21 @@ static int cdns_pcie_ep_start(struct pci_epc *epc)
|
|||||||
cfg |= BIT(epf->func_no);
|
cfg |= BIT(epf->func_no);
|
||||||
cdns_pcie_writel(pcie, CDNS_PCIE_LM_EP_FUNC_CFG, cfg);
|
cdns_pcie_writel(pcie, CDNS_PCIE_LM_EP_FUNC_CFG, cfg);
|
||||||
|
|
||||||
/*
|
|
||||||
* The PCIe links are automatically established by the controller
|
|
||||||
* once for all at powerup: the software can neither start nor stop
|
|
||||||
* those links later at runtime.
|
|
||||||
*
|
|
||||||
* Then we only have to notify the EP core that our links are already
|
|
||||||
* established. However we don't call directly pci_epc_linkup() because
|
|
||||||
* we've already locked the epc->lock.
|
|
||||||
*/
|
|
||||||
list_for_each_entry(epf, &epc->pci_epf, list)
|
|
||||||
pci_epf_linkup(epf);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct pci_epc_features cdns_pcie_epc_features = {
|
||||||
|
.linkup_notifier = false,
|
||||||
|
.msi_capable = true,
|
||||||
|
.msix_capable = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct pci_epc_features*
|
||||||
|
cdns_pcie_ep_get_features(struct pci_epc *epc, u8 func_no)
|
||||||
|
{
|
||||||
|
return &cdns_pcie_epc_features;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct pci_epc_ops cdns_pcie_epc_ops = {
|
static const struct pci_epc_ops cdns_pcie_epc_ops = {
|
||||||
.write_header = cdns_pcie_ep_write_header,
|
.write_header = cdns_pcie_ep_write_header,
|
||||||
.set_bar = cdns_pcie_ep_set_bar,
|
.set_bar = cdns_pcie_ep_set_bar,
|
||||||
@ -421,6 +421,7 @@ static const struct pci_epc_ops cdns_pcie_epc_ops = {
|
|||||||
.get_msi = cdns_pcie_ep_get_msi,
|
.get_msi = cdns_pcie_ep_get_msi,
|
||||||
.raise_irq = cdns_pcie_ep_raise_irq,
|
.raise_irq = cdns_pcie_ep_raise_irq,
|
||||||
.start = cdns_pcie_ep_start,
|
.start = cdns_pcie_ep_start,
|
||||||
|
.get_features = cdns_pcie_ep_get_features,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id cdns_pcie_ep_of_match[] = {
|
static const struct of_device_id cdns_pcie_ep_of_match[] = {
|
||||||
|
@ -499,12 +499,21 @@ static int rockchip_pcie_ep_start(struct pci_epc *epc)
|
|||||||
|
|
||||||
rockchip_pcie_write(rockchip, cfg, PCIE_CORE_PHY_FUNC_CFG);
|
rockchip_pcie_write(rockchip, cfg, PCIE_CORE_PHY_FUNC_CFG);
|
||||||
|
|
||||||
list_for_each_entry(epf, &epc->pci_epf, list)
|
|
||||||
pci_epf_linkup(epf);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct pci_epc_features rockchip_pcie_epc_features = {
|
||||||
|
.linkup_notifier = false,
|
||||||
|
.msi_capable = true,
|
||||||
|
.msix_capable = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct pci_epc_features*
|
||||||
|
rockchip_pcie_ep_get_features(struct pci_epc *epc, u8 func_no)
|
||||||
|
{
|
||||||
|
return &rockchip_pcie_epc_features;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct pci_epc_ops rockchip_pcie_epc_ops = {
|
static const struct pci_epc_ops rockchip_pcie_epc_ops = {
|
||||||
.write_header = rockchip_pcie_ep_write_header,
|
.write_header = rockchip_pcie_ep_write_header,
|
||||||
.set_bar = rockchip_pcie_ep_set_bar,
|
.set_bar = rockchip_pcie_ep_set_bar,
|
||||||
@ -515,6 +524,7 @@ static const struct pci_epc_ops rockchip_pcie_epc_ops = {
|
|||||||
.get_msi = rockchip_pcie_ep_get_msi,
|
.get_msi = rockchip_pcie_ep_get_msi,
|
||||||
.raise_irq = rockchip_pcie_ep_raise_irq,
|
.raise_irq = rockchip_pcie_ep_raise_irq,
|
||||||
.start = rockchip_pcie_ep_start,
|
.start = rockchip_pcie_ep_start,
|
||||||
|
.get_features = rockchip_pcie_ep_get_features,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int rockchip_pcie_parse_ep_dt(struct rockchip_pcie *rockchip,
|
static int rockchip_pcie_parse_ep_dt(struct rockchip_pcie *rockchip,
|
||||||
|
@ -47,9 +47,8 @@ struct pci_epf_test {
|
|||||||
void *reg[6];
|
void *reg[6];
|
||||||
struct pci_epf *epf;
|
struct pci_epf *epf;
|
||||||
enum pci_barno test_reg_bar;
|
enum pci_barno test_reg_bar;
|
||||||
bool linkup_notifier;
|
|
||||||
bool msix_available;
|
|
||||||
struct delayed_work cmd_handler;
|
struct delayed_work cmd_handler;
|
||||||
|
const struct pci_epc_features *epc_features;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pci_epf_test_reg {
|
struct pci_epf_test_reg {
|
||||||
@ -71,11 +70,6 @@ static struct pci_epf_header test_header = {
|
|||||||
.interrupt_pin = PCI_INTERRUPT_INTA,
|
.interrupt_pin = PCI_INTERRUPT_INTA,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pci_epf_test_data {
|
|
||||||
enum pci_barno test_reg_bar;
|
|
||||||
bool linkup_notifier;
|
|
||||||
};
|
|
||||||
|
|
||||||
static size_t bar_size[] = { 512, 512, 1024, 16384, 131072, 1048576 };
|
static size_t bar_size[] = { 512, 512, 1024, 16384, 131072, 1048576 };
|
||||||
|
|
||||||
static int pci_epf_test_copy(struct pci_epf_test *epf_test)
|
static int pci_epf_test_copy(struct pci_epf_test *epf_test)
|
||||||
@ -175,7 +169,7 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
|
|||||||
goto err_map_addr;
|
goto err_map_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(buf, src_addr, reg->size);
|
memcpy_fromio(buf, src_addr, reg->size);
|
||||||
|
|
||||||
crc32 = crc32_le(~0, buf, reg->size);
|
crc32 = crc32_le(~0, buf, reg->size);
|
||||||
if (crc32 != reg->checksum)
|
if (crc32 != reg->checksum)
|
||||||
@ -230,7 +224,7 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
|
|||||||
get_random_bytes(buf, reg->size);
|
get_random_bytes(buf, reg->size);
|
||||||
reg->checksum = crc32_le(~0, buf, reg->size);
|
reg->checksum = crc32_le(~0, buf, reg->size);
|
||||||
|
|
||||||
memcpy(dst_addr, buf, reg->size);
|
memcpy_toio(dst_addr, buf, reg->size);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* wait 1ms inorder for the write to complete. Without this delay L3
|
* wait 1ms inorder for the write to complete. Without this delay L3
|
||||||
@ -402,13 +396,15 @@ static int pci_epf_test_set_bar(struct pci_epf *epf)
|
|||||||
struct device *dev = &epf->dev;
|
struct device *dev = &epf->dev;
|
||||||
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
|
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
|
||||||
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
|
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
|
||||||
|
const struct pci_epc_features *epc_features;
|
||||||
|
|
||||||
|
epc_features = epf_test->epc_features;
|
||||||
|
|
||||||
for (bar = BAR_0; bar <= BAR_5; bar++) {
|
for (bar = BAR_0; bar <= BAR_5; bar++) {
|
||||||
epf_bar = &epf->bar[bar];
|
epf_bar = &epf->bar[bar];
|
||||||
|
|
||||||
epf_bar->flags |= upper_32_bits(epf_bar->size) ?
|
if (!!(epc_features->reserved_bar & (1 << bar)))
|
||||||
PCI_BASE_ADDRESS_MEM_TYPE_64 :
|
continue;
|
||||||
PCI_BASE_ADDRESS_MEM_TYPE_32;
|
|
||||||
|
|
||||||
ret = pci_epc_set_bar(epc, epf->func_no, epf_bar);
|
ret = pci_epc_set_bar(epc, epf->func_no, epf_bar);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@ -433,9 +429,13 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
|
|||||||
{
|
{
|
||||||
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
|
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
|
||||||
struct device *dev = &epf->dev;
|
struct device *dev = &epf->dev;
|
||||||
|
struct pci_epf_bar *epf_bar;
|
||||||
void *base;
|
void *base;
|
||||||
int bar;
|
int bar;
|
||||||
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
|
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
|
||||||
|
const struct pci_epc_features *epc_features;
|
||||||
|
|
||||||
|
epc_features = epf_test->epc_features;
|
||||||
|
|
||||||
base = pci_epf_alloc_space(epf, sizeof(struct pci_epf_test_reg),
|
base = pci_epf_alloc_space(epf, sizeof(struct pci_epf_test_reg),
|
||||||
test_reg_bar);
|
test_reg_bar);
|
||||||
@ -446,37 +446,69 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
|
|||||||
epf_test->reg[test_reg_bar] = base;
|
epf_test->reg[test_reg_bar] = base;
|
||||||
|
|
||||||
for (bar = BAR_0; bar <= BAR_5; bar++) {
|
for (bar = BAR_0; bar <= BAR_5; bar++) {
|
||||||
|
epf_bar = &epf->bar[bar];
|
||||||
if (bar == test_reg_bar)
|
if (bar == test_reg_bar)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (!!(epc_features->reserved_bar & (1 << bar)))
|
||||||
|
continue;
|
||||||
|
|
||||||
base = pci_epf_alloc_space(epf, bar_size[bar], bar);
|
base = pci_epf_alloc_space(epf, bar_size[bar], bar);
|
||||||
if (!base)
|
if (!base)
|
||||||
dev_err(dev, "Failed to allocate space for BAR%d\n",
|
dev_err(dev, "Failed to allocate space for BAR%d\n",
|
||||||
bar);
|
bar);
|
||||||
epf_test->reg[bar] = base;
|
epf_test->reg[bar] = base;
|
||||||
|
if (epf_bar->flags & PCI_BASE_ADDRESS_MEM_TYPE_64)
|
||||||
|
bar++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pci_epf_configure_bar(struct pci_epf *epf,
|
||||||
|
const struct pci_epc_features *epc_features)
|
||||||
|
{
|
||||||
|
struct pci_epf_bar *epf_bar;
|
||||||
|
bool bar_fixed_64bit;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = BAR_0; i <= BAR_5; i++) {
|
||||||
|
epf_bar = &epf->bar[i];
|
||||||
|
bar_fixed_64bit = !!(epc_features->bar_fixed_64bit & (1 << i));
|
||||||
|
if (bar_fixed_64bit)
|
||||||
|
epf_bar->flags |= PCI_BASE_ADDRESS_MEM_TYPE_64;
|
||||||
|
if (epc_features->bar_fixed_size[i])
|
||||||
|
bar_size[i] = epc_features->bar_fixed_size[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int pci_epf_test_bind(struct pci_epf *epf)
|
static int pci_epf_test_bind(struct pci_epf *epf)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
|
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
|
||||||
struct pci_epf_header *header = epf->header;
|
struct pci_epf_header *header = epf->header;
|
||||||
|
const struct pci_epc_features *epc_features;
|
||||||
|
enum pci_barno test_reg_bar = BAR_0;
|
||||||
struct pci_epc *epc = epf->epc;
|
struct pci_epc *epc = epf->epc;
|
||||||
struct device *dev = &epf->dev;
|
struct device *dev = &epf->dev;
|
||||||
|
bool linkup_notifier = false;
|
||||||
|
bool msix_capable = false;
|
||||||
|
bool msi_capable = true;
|
||||||
|
|
||||||
if (WARN_ON_ONCE(!epc))
|
if (WARN_ON_ONCE(!epc))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (epc->features & EPC_FEATURE_NO_LINKUP_NOTIFIER)
|
epc_features = pci_epc_get_features(epc, epf->func_no);
|
||||||
epf_test->linkup_notifier = false;
|
if (epc_features) {
|
||||||
else
|
linkup_notifier = epc_features->linkup_notifier;
|
||||||
epf_test->linkup_notifier = true;
|
msix_capable = epc_features->msix_capable;
|
||||||
|
msi_capable = epc_features->msi_capable;
|
||||||
|
test_reg_bar = pci_epc_get_first_free_bar(epc_features);
|
||||||
|
pci_epf_configure_bar(epf, epc_features);
|
||||||
|
}
|
||||||
|
|
||||||
epf_test->msix_available = epc->features & EPC_FEATURE_MSIX_AVAILABLE;
|
epf_test->test_reg_bar = test_reg_bar;
|
||||||
|
epf_test->epc_features = epc_features;
|
||||||
epf_test->test_reg_bar = EPC_FEATURE_GET_BAR(epc->features);
|
|
||||||
|
|
||||||
ret = pci_epc_write_header(epc, epf->func_no, header);
|
ret = pci_epc_write_header(epc, epf->func_no, header);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@ -492,13 +524,15 @@ static int pci_epf_test_bind(struct pci_epf *epf)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
if (msi_capable) {
|
||||||
ret = pci_epc_set_msi(epc, epf->func_no, epf->msi_interrupts);
|
ret = pci_epc_set_msi(epc, epf->func_no, epf->msi_interrupts);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "MSI configuration failed\n");
|
dev_err(dev, "MSI configuration failed\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (epf_test->msix_available) {
|
if (msix_capable) {
|
||||||
ret = pci_epc_set_msix(epc, epf->func_no, epf->msix_interrupts);
|
ret = pci_epc_set_msix(epc, epf->func_no, epf->msix_interrupts);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "MSI-X configuration failed\n");
|
dev_err(dev, "MSI-X configuration failed\n");
|
||||||
@ -506,7 +540,7 @@ static int pci_epf_test_bind(struct pci_epf *epf)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!epf_test->linkup_notifier)
|
if (!linkup_notifier)
|
||||||
queue_work(kpcitest_workqueue, &epf_test->cmd_handler.work);
|
queue_work(kpcitest_workqueue, &epf_test->cmd_handler.work);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -523,17 +557,6 @@ static int pci_epf_test_probe(struct pci_epf *epf)
|
|||||||
{
|
{
|
||||||
struct pci_epf_test *epf_test;
|
struct pci_epf_test *epf_test;
|
||||||
struct device *dev = &epf->dev;
|
struct device *dev = &epf->dev;
|
||||||
const struct pci_epf_device_id *match;
|
|
||||||
struct pci_epf_test_data *data;
|
|
||||||
enum pci_barno test_reg_bar = BAR_0;
|
|
||||||
bool linkup_notifier = true;
|
|
||||||
|
|
||||||
match = pci_epf_match_device(pci_epf_test_ids, epf);
|
|
||||||
data = (struct pci_epf_test_data *)match->driver_data;
|
|
||||||
if (data) {
|
|
||||||
test_reg_bar = data->test_reg_bar;
|
|
||||||
linkup_notifier = data->linkup_notifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
epf_test = devm_kzalloc(dev, sizeof(*epf_test), GFP_KERNEL);
|
epf_test = devm_kzalloc(dev, sizeof(*epf_test), GFP_KERNEL);
|
||||||
if (!epf_test)
|
if (!epf_test)
|
||||||
@ -541,8 +564,6 @@ static int pci_epf_test_probe(struct pci_epf *epf)
|
|||||||
|
|
||||||
epf->header = &test_header;
|
epf->header = &test_header;
|
||||||
epf_test->epf = epf;
|
epf_test->epf = epf;
|
||||||
epf_test->test_reg_bar = test_reg_bar;
|
|
||||||
epf_test->linkup_notifier = linkup_notifier;
|
|
||||||
|
|
||||||
INIT_DELAYED_WORK(&epf_test->cmd_handler, pci_epf_test_cmd_handler);
|
INIT_DELAYED_WORK(&epf_test->cmd_handler, pci_epf_test_cmd_handler);
|
||||||
|
|
||||||
|
@ -83,6 +83,59 @@ err:
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pci_epc_get);
|
EXPORT_SYMBOL_GPL(pci_epc_get);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pci_epc_get_first_free_bar() - helper to get first unreserved BAR
|
||||||
|
* @epc_features: pci_epc_features structure that holds the reserved bar bitmap
|
||||||
|
*
|
||||||
|
* Invoke to get the first unreserved BAR that can be used for endpoint
|
||||||
|
* function. For any incorrect value in reserved_bar return '0'.
|
||||||
|
*/
|
||||||
|
unsigned int pci_epc_get_first_free_bar(const struct pci_epc_features
|
||||||
|
*epc_features)
|
||||||
|
{
|
||||||
|
int free_bar;
|
||||||
|
|
||||||
|
if (!epc_features)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
free_bar = ffz(epc_features->reserved_bar);
|
||||||
|
if (free_bar > 5)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return free_bar;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(pci_epc_get_first_free_bar);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pci_epc_get_features() - get the features supported by EPC
|
||||||
|
* @epc: the features supported by *this* EPC device will be returned
|
||||||
|
* @func_no: the features supported by the EPC device specific to the
|
||||||
|
* endpoint function with func_no will be returned
|
||||||
|
*
|
||||||
|
* Invoke to get the features provided by the EPC which may be
|
||||||
|
* specific to an endpoint function. Returns pci_epc_features on success
|
||||||
|
* and NULL for any failures.
|
||||||
|
*/
|
||||||
|
const struct pci_epc_features *pci_epc_get_features(struct pci_epc *epc,
|
||||||
|
u8 func_no)
|
||||||
|
{
|
||||||
|
const struct pci_epc_features *epc_features;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!epc->ops->get_features)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&epc->lock, flags);
|
||||||
|
epc_features = epc->ops->get_features(epc, func_no);
|
||||||
|
spin_unlock_irqrestore(&epc->lock, flags);
|
||||||
|
|
||||||
|
return epc_features;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(pci_epc_get_features);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pci_epc_stop() - stop the PCI link
|
* pci_epc_stop() - stop the PCI link
|
||||||
* @epc: the link of the EPC device that has to be stopped
|
* @epc: the link of the EPC device that has to be stopped
|
||||||
|
@ -131,7 +131,9 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar)
|
|||||||
epf->bar[bar].phys_addr = phys_addr;
|
epf->bar[bar].phys_addr = phys_addr;
|
||||||
epf->bar[bar].size = size;
|
epf->bar[bar].size = size;
|
||||||
epf->bar[bar].barno = bar;
|
epf->bar[bar].barno = bar;
|
||||||
epf->bar[bar].flags = PCI_BASE_ADDRESS_SPACE_MEMORY;
|
epf->bar[bar].flags |= upper_32_bits(size) ?
|
||||||
|
PCI_BASE_ADDRESS_MEM_TYPE_64 :
|
||||||
|
PCI_BASE_ADDRESS_MEM_TYPE_32;
|
||||||
|
|
||||||
return space;
|
return space;
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,8 @@ struct pci_epc_ops {
|
|||||||
enum pci_epc_irq_type type, u16 interrupt_num);
|
enum pci_epc_irq_type type, u16 interrupt_num);
|
||||||
int (*start)(struct pci_epc *epc);
|
int (*start)(struct pci_epc *epc);
|
||||||
void (*stop)(struct pci_epc *epc);
|
void (*stop)(struct pci_epc *epc);
|
||||||
|
const struct pci_epc_features* (*get_features)(struct pci_epc *epc,
|
||||||
|
u8 func_no);
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -97,16 +99,25 @@ struct pci_epc {
|
|||||||
struct config_group *group;
|
struct config_group *group;
|
||||||
/* spinlock to protect against concurrent access of EP controller */
|
/* spinlock to protect against concurrent access of EP controller */
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
unsigned int features;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define EPC_FEATURE_NO_LINKUP_NOTIFIER BIT(0)
|
/**
|
||||||
#define EPC_FEATURE_BAR_MASK (BIT(1) | BIT(2) | BIT(3))
|
* struct pci_epc_features - features supported by a EPC device per function
|
||||||
#define EPC_FEATURE_MSIX_AVAILABLE BIT(4)
|
* @linkup_notifier: indicate if the EPC device can notify EPF driver on link up
|
||||||
#define EPC_FEATURE_SET_BAR(features, bar) \
|
* @msi_capable: indicate if the endpoint function has MSI capability
|
||||||
(features |= (EPC_FEATURE_BAR_MASK & (bar << 1)))
|
* @msix_capable: indicate if the endpoint function has MSI-X capability
|
||||||
#define EPC_FEATURE_GET_BAR(features) \
|
* @reserved_bar: bitmap to indicate reserved BAR unavailable to function driver
|
||||||
((features & EPC_FEATURE_BAR_MASK) >> 1)
|
* @bar_fixed_64bit: bitmap to indicate fixed 64bit BARs
|
||||||
|
* @bar_fixed_size: Array specifying the size supported by each BAR
|
||||||
|
*/
|
||||||
|
struct pci_epc_features {
|
||||||
|
unsigned int linkup_notifier : 1;
|
||||||
|
unsigned int msi_capable : 1;
|
||||||
|
unsigned int msix_capable : 1;
|
||||||
|
u8 reserved_bar;
|
||||||
|
u8 bar_fixed_64bit;
|
||||||
|
u64 bar_fixed_size[BAR_5 + 1];
|
||||||
|
};
|
||||||
|
|
||||||
#define to_pci_epc(device) container_of((device), struct pci_epc, dev)
|
#define to_pci_epc(device) container_of((device), struct pci_epc, dev)
|
||||||
|
|
||||||
@ -158,6 +169,10 @@ int pci_epc_raise_irq(struct pci_epc *epc, u8 func_no,
|
|||||||
enum pci_epc_irq_type type, u16 interrupt_num);
|
enum pci_epc_irq_type type, u16 interrupt_num);
|
||||||
int pci_epc_start(struct pci_epc *epc);
|
int pci_epc_start(struct pci_epc *epc);
|
||||||
void pci_epc_stop(struct pci_epc *epc);
|
void pci_epc_stop(struct pci_epc *epc);
|
||||||
|
const struct pci_epc_features *pci_epc_get_features(struct pci_epc *epc,
|
||||||
|
u8 func_no);
|
||||||
|
unsigned int pci_epc_get_first_free_bar(const struct pci_epc_features
|
||||||
|
*epc_features);
|
||||||
struct pci_epc *pci_epc_get(const char *epc_name);
|
struct pci_epc *pci_epc_get(const char *epc_name);
|
||||||
void pci_epc_put(struct pci_epc *epc);
|
void pci_epc_put(struct pci_epc *epc);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user