mirror of
https://github.com/FEX-Emu/linux.git
synced 2025-01-23 11:08:07 +00:00
Merge branch 'remotes/lorenzo/pci/keystone'
- Move IRQ register address computation inside macros (Kishon Vijay Abraham I) - Separate legacy IRQ and MSI configuration (Kishon Vijay Abraham I) - Use hwirq, not virq, to get MSI IRQ number offset (Kishon Vijay Abraham I) - Squash ks_pcie_handle_msi_irq() into ks_pcie_msi_irq_handler() (Kishon Vijay Abraham I) - Add dwc support for platforms with custom MSI controllers (Kishon Vijay Abraham I) - Add keystone-specific MSI controller (Kishon Vijay Abraham I) - Remove dwc host_ops previously used for keystone-specific MSI (Kishon Vijay Abraham I) - Skip dwc default MSI init if platform has custom MSI controller (Kishon Vijay Abraham I) - Implement .start_link() and .stop_link() for keystone endpoint support (Kishon Vijay Abraham I) - Add keystone "reg-names" DT binding (Kishon Vijay Abraham I) - Squash ks_pcie_dw_host_init() into ks_pcie_add_pcie_port() (Kishon Vijay Abraham I) - Get keystone register resources from DT by name, not index (Kishon Vijay Abraham I) - Get DT resources in .probe() to prepare for endpoint support (Kishon Vijay Abraham I) - Add "ti,syscon-pcie-mode" DT property for PCIe mode configuration (Kishon Vijay Abraham I) - Explicitly set keystone to host mode (Kishon Vijay Abraham I) - Document DT "atu" reg-names requirement for DesignWare core >= 4.80 (Kishon Vijay Abraham I) - Enable dwc iATU unroll for endpoint mode as well as host mode (Kishon Vijay Abraham I) - Add dwc "version" to identify core >= 4.80 for ATU programming (Kishon Vijay Abraham I) - Don't build ARM32-specific keystone code on ARM64 (Kishon Vijay Abraham I) - Add DT binding for keystone PCIe RC in AM654 SoC (Kishon Vijay Abraham I) - Add keystone support for AM654 SoC PCIe RC (Kishon Vijay Abraham I) - Reset keystone PHYs before enabling them (Kishon Vijay Abraham I) - Make of_pci_get_max_link_speed() available to endpoint drivers as well as host drivers (Kishon Vijay Abraham I) - Add keystone support for DT "max-link-speed" property (Kishon Vijay Abraham I) - Add endpoint library support for BAR buffer alignment (Kishon Vijay Abraham I) - Make all dw_pcie_ep_ops structs const (Kishon Vijay Abraham I) - Fix fencepost error in dw_pcie_ep_find_capability() (Kishon Vijay Abraham I) - Add dwc hooks for dbi/dbi2 that share the same address space (Kishon Vijay Abraham I) - Add keystone support for TI AM654x in endpoint mode (Kishon Vijay Abraham I) - Configure designware endpoints to advertise smallest resizable BAR (1MB) (Kishon Vijay Abraham I) - Align designware endpoint ATU windows for raising MSIs (Kishon Vijay Abraham I) - Add endpoint test support for TI AM654x (Kishon Vijay Abraham I) - Fix endpoint test test_reg_bar issue (Kishon Vijay Abraham I) * remotes/lorenzo/pci/keystone: misc: pci_endpoint_test: Fix test_reg_bar to be updated in pci_endpoint_test misc: pci_endpoint_test: Add support to test PCI EP in AM654x PCI: designware-ep: Use aligned ATU window for raising MSI interrupts PCI: designware-ep: Configure Resizable BAR cap to advertise the smallest size PCI: keystone: Add support for PCIe EP in AM654x Platforms dt-bindings: PCI: Add PCI EP DT binding documentation for AM654 PCI: dwc: Add callbacks for accessing dbi2 address space PCI: dwc: Fix dw_pcie_ep_find_capability() to return correct capability offset PCI: dwc: Add const qualifier to struct dw_pcie_ep_ops PCI: endpoint: Add support to specify alignment for buffers allocated to BARs PCI: keystone: Add support to set the max link speed from DT PCI: OF: Allow of_pci_get_max_link_speed() to be used by PCI Endpoint drivers PCI: keystone: Invoke phy_reset() API before enabling PHY PCI: keystone: Add support for PCIe RC in AM654x Platforms dt-bindings: PCI: Add PCI RC DT binding documentation for AM654 PCI: keystone: Prevent ARM32 specific code to be compiled for ARM64 PCI: dwc: Fix ATU identification for designware version >= 4.80 PCI: dwc: Enable iATU unroll for endpoint too dt-bindings: PCI: Document "atu" reg-names PCI: keystone: Explicitly set the PCIe mode dt-bindings: PCI: Add dt-binding to configure PCIe mode PCI: keystone: Move resources initialization to prepare for EP support PCI: keystone: Use platform_get_resource_byname() to get memory resources PCI: keystone: Perform host initialization in a single function dt-bindings: PCI: keystone: Add "reg-names" binding information PCI: keystone: Cleanup error_irq configuration PCI: keystone: Add start_link()/stop_link() dw_pcie_ops PCI: dwc: Remove default MSI initialization for platform specific MSI chips PCI: dwc: Remove Keystone specific dw_pcie_host_ops PCI: keystone: Use Keystone specific msi_irq_chip PCI: dwc: Add support to use non default msi_irq_chip PCI: keystone: Cleanup ks_pcie_msi_irq_handler() PCI: keystone: Use hwirq to get the MSI IRQ number offset PCI: keystone: Add separate functions for configuring MSI and legacy interrupt PCI: keystone: Cleanup interrupt related macros # Conflicts: # drivers/pci/controller/dwc/pcie-designware.h
This commit is contained in:
commit
0b8439d374
@ -4,8 +4,11 @@ Required properties:
|
||||
- compatible:
|
||||
"snps,dw-pcie" for RC mode;
|
||||
"snps,dw-pcie-ep" for EP mode;
|
||||
- reg: Should contain the configuration address space.
|
||||
- reg-names: Must be "config" for the PCIe configuration space.
|
||||
- reg: For designware cores version < 4.80 contains the configuration
|
||||
address space. For designware core version >= 4.80, contains
|
||||
the configuration and ATU address space
|
||||
- reg-names: Must be "config" for the PCIe configuration space and "atu" for
|
||||
the ATU address space.
|
||||
(The old way of getting the configuration address space from "ranges"
|
||||
is deprecated and should be avoided.)
|
||||
- num-lanes: number of lanes to use
|
||||
|
@ -11,16 +11,24 @@ described here as well as properties that are not applicable.
|
||||
|
||||
Required Properties:-
|
||||
|
||||
compatibility: "ti,keystone-pcie"
|
||||
reg: index 1 is the base address and length of DW application registers.
|
||||
index 2 is the base address and length of PCI device ID register.
|
||||
compatibility: Should be "ti,keystone-pcie" for RC on Keystone2 SoC
|
||||
Should be "ti,am654-pcie-rc" for RC on AM654x SoC
|
||||
reg: Three register ranges as listed in the reg-names property
|
||||
reg-names: "dbics" for the DesignWare PCIe registers, "app" for the
|
||||
TI specific application registers, "config" for the
|
||||
configuration space address
|
||||
|
||||
pcie_msi_intc : Interrupt controller device node for MSI IRQ chip
|
||||
interrupt-cells: should be set to 1
|
||||
interrupts: GIC interrupt lines connected to PCI MSI interrupt lines
|
||||
(required if the compatible is "ti,keystone-pcie")
|
||||
msi-map: As specified in Documentation/devicetree/bindings/pci/pci-msi.txt
|
||||
(required if the compatible is "ti,am654-pcie-rc".
|
||||
|
||||
ti,syscon-pcie-id : phandle to the device control module required to set device
|
||||
id and vendor id.
|
||||
ti,syscon-pcie-mode : phandle to the device control module required to configure
|
||||
PCI in either RC mode or EP mode.
|
||||
|
||||
Example:
|
||||
pcie_msi_intc: msi-interrupt-controller {
|
||||
@ -61,3 +69,47 @@ Optional properties:-
|
||||
DesignWare DT Properties not applicable for Keystone PCI
|
||||
|
||||
1. pcie_bus clock-names not used. Instead, a phandle to phys is used.
|
||||
|
||||
AM654 PCIe Endpoint
|
||||
===================
|
||||
|
||||
Required Properties:-
|
||||
|
||||
compatibility: Should be "ti,am654-pcie-ep" for EP on AM654x SoC
|
||||
reg: Four register ranges as listed in the reg-names property
|
||||
reg-names: "dbics" for the DesignWare PCIe registers, "app" for the
|
||||
TI specific application registers, "atu" for the
|
||||
Address Translation Unit configuration registers and
|
||||
"addr_space" used to map remote RC address space
|
||||
num-ib-windows: As specified in
|
||||
Documentation/devicetree/bindings/pci/designware-pcie.txt
|
||||
num-ob-windows: As specified in
|
||||
Documentation/devicetree/bindings/pci/designware-pcie.txt
|
||||
num-lanes: As specified in
|
||||
Documentation/devicetree/bindings/pci/designware-pcie.txt
|
||||
power-domains: As documented by the generic PM domain bindings in
|
||||
Documentation/devicetree/bindings/power/power_domain.txt.
|
||||
ti,syscon-pcie-mode: phandle to the device control module required to configure
|
||||
PCI in either RC mode or EP mode.
|
||||
|
||||
Optional properties:-
|
||||
|
||||
phys: list of PHY specifiers (used by generic PHY framework)
|
||||
phy-names: must be "pcie-phy0", "pcie-phy1", "pcie-phyN".. based on the
|
||||
number of lanes as specified in *num-lanes* property.
|
||||
("phys" and "phy-names" DT bindings are specified in
|
||||
Documentation/devicetree/bindings/phy/phy-bindings.txt)
|
||||
interrupts: platform interrupt for error interrupts.
|
||||
|
||||
pcie-ep {
|
||||
compatible = "ti,am654-pcie-ep";
|
||||
reg = <0x5500000 0x1000>, <0x5501000 0x1000>,
|
||||
<0x10000000 0x8000000>, <0x5506000 0x1000>;
|
||||
reg-names = "app", "dbics", "addr_space", "atu";
|
||||
power-domains = <&k3_pds 120>;
|
||||
ti,syscon-pcie-mode = <&pcie0_mode>;
|
||||
num-lanes = <1>;
|
||||
num-ib-windows = <16>;
|
||||
num-ob-windows = <16>;
|
||||
interrupts = <GIC_SPI 340 IRQ_TYPE_EDGE_RISING>;
|
||||
};
|
||||
|
@ -75,6 +75,11 @@
|
||||
#define PCI_ENDPOINT_TEST_IRQ_TYPE 0x24
|
||||
#define PCI_ENDPOINT_TEST_IRQ_NUMBER 0x28
|
||||
|
||||
#define PCI_DEVICE_ID_TI_AM654 0xb00c
|
||||
|
||||
#define is_am654_pci_dev(pdev) \
|
||||
((pdev)->device == PCI_DEVICE_ID_TI_AM654)
|
||||
|
||||
static DEFINE_IDA(pci_endpoint_test_ida);
|
||||
|
||||
#define to_endpoint_test(priv) container_of((priv), struct pci_endpoint_test, \
|
||||
@ -588,6 +593,7 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
|
||||
int ret = -EINVAL;
|
||||
enum pci_barno bar;
|
||||
struct pci_endpoint_test *test = to_endpoint_test(file->private_data);
|
||||
struct pci_dev *pdev = test->pdev;
|
||||
|
||||
mutex_lock(&test->mutex);
|
||||
switch (cmd) {
|
||||
@ -595,6 +601,8 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
|
||||
bar = arg;
|
||||
if (bar < 0 || bar > 5)
|
||||
goto ret;
|
||||
if (is_am654_pci_dev(pdev) && bar == BAR_0)
|
||||
goto ret;
|
||||
ret = pci_endpoint_test_bar(test, bar);
|
||||
break;
|
||||
case PCITEST_LEGACY_IRQ:
|
||||
@ -662,6 +670,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
|
||||
data = (struct pci_endpoint_test_data *)ent->driver_data;
|
||||
if (data) {
|
||||
test_reg_bar = data->test_reg_bar;
|
||||
test->test_reg_bar = test_reg_bar;
|
||||
test->alignment = data->alignment;
|
||||
irq_type = data->irq_type;
|
||||
}
|
||||
@ -785,11 +794,20 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev)
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
static const struct pci_endpoint_test_data am654_data = {
|
||||
.test_reg_bar = BAR_2,
|
||||
.alignment = SZ_64K,
|
||||
.irq_type = IRQ_TYPE_MSI,
|
||||
};
|
||||
|
||||
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_DRA72x) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, 0xedda) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654),
|
||||
.driver_data = (kernel_ulong_t)&am654_data
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, pci_endpoint_test_tbl);
|
||||
|
@ -10,10 +10,10 @@ obj-$(CONFIG_PCI) += access.o bus.o probe.o host-bridge.o \
|
||||
ifdef CONFIG_PCI
|
||||
obj-$(CONFIG_PROC_FS) += proc.o
|
||||
obj-$(CONFIG_SYSFS) += slot.o
|
||||
obj-$(CONFIG_OF) += of.o
|
||||
obj-$(CONFIG_ACPI) += pci-acpi.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_OF) += of.o
|
||||
obj-$(CONFIG_PCI_QUIRKS) += quirks.o
|
||||
obj-$(CONFIG_PCIEPORTBUS) += pcie/
|
||||
obj-$(CONFIG_HOTPLUG_PCI) += hotplug/
|
||||
|
@ -103,15 +103,32 @@ config PCIE_SPEAR13XX
|
||||
Say Y here if you want PCIe support on SPEAr13XX SoCs.
|
||||
|
||||
config PCI_KEYSTONE
|
||||
bool "TI Keystone PCIe controller"
|
||||
depends on ARCH_KEYSTONE || (ARM && COMPILE_TEST)
|
||||
bool
|
||||
|
||||
config PCI_KEYSTONE_HOST
|
||||
bool "PCI Keystone Host Mode"
|
||||
depends on ARCH_KEYSTONE || ARCH_K3 || ((ARM || ARM64) && COMPILE_TEST)
|
||||
depends on PCI_MSI_IRQ_DOMAIN
|
||||
select PCIE_DW_HOST
|
||||
select PCI_KEYSTONE
|
||||
default y
|
||||
help
|
||||
Say Y here if you want to enable PCI controller support on Keystone
|
||||
SoCs. The PCI controller on Keystone is based on DesignWare hardware
|
||||
and therefore the driver re-uses the DesignWare core functions to
|
||||
implement the driver.
|
||||
Enables support for the PCIe controller in the Keystone SoC to
|
||||
work in host mode. The PCI controller on Keystone is based on
|
||||
DesignWare hardware and therefore the driver re-uses the
|
||||
DesignWare core functions to implement the driver.
|
||||
|
||||
config PCI_KEYSTONE_EP
|
||||
bool "PCI Keystone Endpoint Mode"
|
||||
depends on ARCH_KEYSTONE || ARCH_K3 || ((ARM || ARM64) && COMPILE_TEST)
|
||||
depends on PCI_ENDPOINT
|
||||
select PCIE_DW_EP
|
||||
select PCI_KEYSTONE
|
||||
help
|
||||
Enables support for the PCIe controller in the Keystone SoC to
|
||||
work in endpoint mode. The PCI controller on Keystone is based
|
||||
on DesignWare hardware and therefore the driver re-uses the
|
||||
DesignWare core functions to implement the driver.
|
||||
|
||||
config PCI_LAYERSCAPE
|
||||
bool "Freescale Layerscape PCIe controller"
|
||||
|
@ -406,7 +406,7 @@ dra7xx_pcie_get_features(struct dw_pcie_ep *ep)
|
||||
return &dra7xx_pcie_epc_features;
|
||||
}
|
||||
|
||||
static struct dw_pcie_ep_ops pcie_ep_ops = {
|
||||
static const struct dw_pcie_ep_ops pcie_ep_ops = {
|
||||
.ep_init = dra7xx_pcie_ep_init,
|
||||
.raise_irq = dra7xx_pcie_raise_irq,
|
||||
.get_features = dra7xx_pcie_get_features,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -79,7 +79,7 @@ static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
}
|
||||
}
|
||||
|
||||
static struct dw_pcie_ep_ops pcie_ep_ops = {
|
||||
static const 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,
|
||||
|
@ -444,7 +444,7 @@ static int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dw_pcie_ep_ops pcie_ep_ops = {
|
||||
static const struct dw_pcie_ep_ops pcie_ep_ops = {
|
||||
.ep_init = artpec6_pcie_ep_init,
|
||||
.raise_irq = artpec6_pcie_raise_irq,
|
||||
};
|
||||
|
@ -46,16 +46,19 @@ static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie *pci, u8 cap_ptr,
|
||||
u8 cap_id, next_cap_ptr;
|
||||
u16 reg;
|
||||
|
||||
if (!cap_ptr)
|
||||
return 0;
|
||||
|
||||
reg = dw_pcie_readw_dbi(pci, cap_ptr);
|
||||
next_cap_ptr = (reg & 0xff00) >> 8;
|
||||
cap_id = (reg & 0x00ff);
|
||||
|
||||
if (!next_cap_ptr || cap_id > PCI_CAP_ID_MAX)
|
||||
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(pci, next_cap_ptr, cap);
|
||||
}
|
||||
|
||||
@ -67,9 +70,6 @@ static u8 dw_pcie_ep_find_capability(struct dw_pcie *pci, u8 cap)
|
||||
reg = dw_pcie_readw_dbi(pci, PCI_CAPABILITY_LIST);
|
||||
next_cap_ptr = (reg & 0x00ff);
|
||||
|
||||
if (!next_cap_ptr)
|
||||
return 0;
|
||||
|
||||
return __dw_pcie_ep_find_next_cap(pci, next_cap_ptr, cap);
|
||||
}
|
||||
|
||||
@ -397,6 +397,7 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
struct pci_epc *epc = ep->epc;
|
||||
unsigned int aligned_offset;
|
||||
u16 msg_ctrl, msg_data;
|
||||
u32 msg_addr_lower, msg_addr_upper, reg;
|
||||
u64 msg_addr;
|
||||
@ -422,13 +423,15 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
reg = ep->msi_cap + PCI_MSI_DATA_32;
|
||||
msg_data = dw_pcie_readw_dbi(pci, reg);
|
||||
}
|
||||
msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower;
|
||||
aligned_offset = msg_addr_lower & (epc->mem->page_size - 1);
|
||||
msg_addr = ((u64)msg_addr_upper) << 32 |
|
||||
(msg_addr_lower & ~aligned_offset);
|
||||
ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr,
|
||||
epc->mem->page_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
writel(msg_data | (interrupt_num - 1), ep->msi_mem);
|
||||
writel(msg_data | (interrupt_num - 1), ep->msi_mem + aligned_offset);
|
||||
|
||||
dw_pcie_ep_unmap_addr(epc, func_no, ep->msi_mem_phys);
|
||||
|
||||
@ -504,10 +507,32 @@ void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
|
||||
pci_epc_mem_exit(epc);
|
||||
}
|
||||
|
||||
static unsigned int dw_pcie_ep_find_ext_capability(struct dw_pcie *pci, int cap)
|
||||
{
|
||||
u32 header;
|
||||
int pos = PCI_CFG_SPACE_SIZE;
|
||||
|
||||
while (pos) {
|
||||
header = dw_pcie_readl_dbi(pci, pos);
|
||||
if (PCI_EXT_CAP_ID(header) == cap)
|
||||
return pos;
|
||||
|
||||
pos = PCI_EXT_CAP_NEXT(header);
|
||||
if (!pos)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
u32 reg;
|
||||
void *addr;
|
||||
unsigned int nbars;
|
||||
unsigned int offset;
|
||||
struct pci_epc *epc;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
struct device *dev = pci->dev;
|
||||
@ -517,10 +542,6 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
dev_err(dev, "dbi_base/dbi_base2 is not populated\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (pci->iatu_unroll_enabled && !pci->atu_base) {
|
||||
dev_err(dev, "atu_base is not populated\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "num-ib-windows", &ep->num_ib_windows);
|
||||
if (ret < 0) {
|
||||
@ -595,6 +616,18 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
|
||||
ep->msix_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSIX);
|
||||
|
||||
offset = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR);
|
||||
if (offset) {
|
||||
reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL);
|
||||
nbars = (reg & PCI_REBAR_CTRL_NBAR_MASK) >>
|
||||
PCI_REBAR_CTRL_NBAR_SHIFT;
|
||||
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
for (i = 0; i < nbars; i++, offset += PCI_REBAR_CTRL)
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_REBAR_CAP, 0x0);
|
||||
dw_pcie_dbi_ro_wr_dis(pci);
|
||||
}
|
||||
|
||||
dw_pcie_setup(pci);
|
||||
|
||||
return 0;
|
||||
|
@ -126,18 +126,12 @@ static void dw_pci_setup_msi_msg(struct irq_data *d, struct msi_msg *msg)
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
u64 msi_target;
|
||||
|
||||
if (pp->ops->get_msi_addr)
|
||||
msi_target = pp->ops->get_msi_addr(pp);
|
||||
else
|
||||
msi_target = (u64)pp->msi_data;
|
||||
msi_target = (u64)pp->msi_data;
|
||||
|
||||
msg->address_lo = lower_32_bits(msi_target);
|
||||
msg->address_hi = upper_32_bits(msi_target);
|
||||
|
||||
if (pp->ops->get_msi_data)
|
||||
msg->data = pp->ops->get_msi_data(pp, d->hwirq);
|
||||
else
|
||||
msg->data = d->hwirq;
|
||||
msg->data = d->hwirq;
|
||||
|
||||
dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n",
|
||||
(int)d->hwirq, msg->address_hi, msg->address_lo);
|
||||
@ -157,17 +151,13 @@ static void dw_pci_bottom_mask(struct irq_data *d)
|
||||
|
||||
raw_spin_lock_irqsave(&pp->lock, flags);
|
||||
|
||||
if (pp->ops->msi_clear_irq) {
|
||||
pp->ops->msi_clear_irq(pp, d->hwirq);
|
||||
} else {
|
||||
ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
|
||||
res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
|
||||
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
|
||||
ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
|
||||
res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
|
||||
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
|
||||
|
||||
pp->irq_mask[ctrl] |= BIT(bit);
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
|
||||
pp->irq_mask[ctrl]);
|
||||
}
|
||||
pp->irq_mask[ctrl] |= BIT(bit);
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
|
||||
pp->irq_mask[ctrl]);
|
||||
|
||||
raw_spin_unlock_irqrestore(&pp->lock, flags);
|
||||
}
|
||||
@ -180,17 +170,13 @@ static void dw_pci_bottom_unmask(struct irq_data *d)
|
||||
|
||||
raw_spin_lock_irqsave(&pp->lock, flags);
|
||||
|
||||
if (pp->ops->msi_set_irq) {
|
||||
pp->ops->msi_set_irq(pp, d->hwirq);
|
||||
} else {
|
||||
ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
|
||||
res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
|
||||
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
|
||||
ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
|
||||
res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
|
||||
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
|
||||
|
||||
pp->irq_mask[ctrl] &= ~BIT(bit);
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
|
||||
pp->irq_mask[ctrl]);
|
||||
}
|
||||
pp->irq_mask[ctrl] &= ~BIT(bit);
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
|
||||
pp->irq_mask[ctrl]);
|
||||
|
||||
raw_spin_unlock_irqrestore(&pp->lock, flags);
|
||||
}
|
||||
@ -199,20 +185,12 @@ static void dw_pci_bottom_ack(struct irq_data *d)
|
||||
{
|
||||
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
|
||||
unsigned int res, bit, ctrl;
|
||||
unsigned long flags;
|
||||
|
||||
ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
|
||||
res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
|
||||
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
|
||||
|
||||
raw_spin_lock_irqsave(&pp->lock, flags);
|
||||
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + res, 4, BIT(bit));
|
||||
|
||||
if (pp->ops->msi_irq_ack)
|
||||
pp->ops->msi_irq_ack(d->hwirq, pp);
|
||||
|
||||
raw_spin_unlock_irqrestore(&pp->lock, flags);
|
||||
}
|
||||
|
||||
static struct irq_chip dw_pci_msi_bottom_irq_chip = {
|
||||
@ -245,7 +223,7 @@ static int dw_pcie_irq_domain_alloc(struct irq_domain *domain,
|
||||
|
||||
for (i = 0; i < nr_irqs; i++)
|
||||
irq_domain_set_info(domain, virq + i, bit + i,
|
||||
&dw_pci_msi_bottom_irq_chip,
|
||||
pp->msi_irq_chip,
|
||||
pp, handle_edge_irq,
|
||||
NULL, NULL);
|
||||
|
||||
@ -462,6 +440,8 @@ int dw_pcie_host_init(struct pcie_port *pp)
|
||||
}
|
||||
|
||||
if (!pp->ops->msi_host_init) {
|
||||
pp->msi_irq_chip = &dw_pci_msi_bottom_irq_chip;
|
||||
|
||||
ret = dw_pcie_allocate_domains(pp);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -632,17 +612,6 @@ static struct pci_ops dw_pcie_ops = {
|
||||
.write = dw_pcie_wr_conf,
|
||||
};
|
||||
|
||||
static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT);
|
||||
if (val == 0xffffffff)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dw_pcie_setup_rc(struct pcie_port *pp)
|
||||
{
|
||||
u32 val, ctrl, num_ctrls;
|
||||
@ -650,17 +619,19 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
|
||||
|
||||
dw_pcie_setup(pci);
|
||||
|
||||
num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
|
||||
if (!pp->ops->msi_host_init) {
|
||||
num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
|
||||
|
||||
/* Initialize IRQ Status array */
|
||||
for (ctrl = 0; ctrl < num_ctrls; ctrl++) {
|
||||
pp->irq_mask[ctrl] = ~0;
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK +
|
||||
(ctrl * MSI_REG_CTRL_BLOCK_SIZE),
|
||||
4, pp->irq_mask[ctrl]);
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE +
|
||||
(ctrl * MSI_REG_CTRL_BLOCK_SIZE),
|
||||
4, ~0);
|
||||
/* Initialize IRQ Status array */
|
||||
for (ctrl = 0; ctrl < num_ctrls; ctrl++) {
|
||||
pp->irq_mask[ctrl] = ~0;
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK +
|
||||
(ctrl * MSI_REG_CTRL_BLOCK_SIZE),
|
||||
4, pp->irq_mask[ctrl]);
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE +
|
||||
(ctrl * MSI_REG_CTRL_BLOCK_SIZE),
|
||||
4, ~0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup RC BARs */
|
||||
@ -694,14 +665,6 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
|
||||
* we should not program the ATU here.
|
||||
*/
|
||||
if (!pp->ops->rd_other_conf) {
|
||||
/* Get iATU unroll support */
|
||||
pci->iatu_unroll_enabled = dw_pcie_iatu_unroll_enabled(pci);
|
||||
dev_dbg(pci->dev, "iATU unroll: %s\n",
|
||||
pci->iatu_unroll_enabled ? "enabled" : "disabled");
|
||||
|
||||
if (pci->iatu_unroll_enabled && !pci->atu_base)
|
||||
pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
|
||||
|
||||
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
|
||||
PCIE_ATU_TYPE_MEM, pp->mem_base,
|
||||
pp->mem_bus_addr, pp->mem_size);
|
||||
|
@ -106,7 +106,7 @@ 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 const struct dw_pcie_ep_ops pcie_ep_ops = {
|
||||
.ep_init = dw_plat_pcie_ep_init,
|
||||
.raise_irq = dw_plat_pcie_ep_raise_irq,
|
||||
.get_features = dw_plat_pcie_get_features,
|
||||
|
@ -83,6 +83,37 @@ void __dw_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg,
|
||||
dev_err(pci->dev, "Write DBI address failed\n");
|
||||
}
|
||||
|
||||
u32 __dw_pcie_read_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg,
|
||||
size_t size)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
if (pci->ops->read_dbi2)
|
||||
return pci->ops->read_dbi2(pci, base, reg, size);
|
||||
|
||||
ret = dw_pcie_read(base + reg, size, &val);
|
||||
if (ret)
|
||||
dev_err(pci->dev, "read DBI address failed\n");
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void __dw_pcie_write_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg,
|
||||
size_t size, u32 val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (pci->ops->write_dbi2) {
|
||||
pci->ops->write_dbi2(pci, base, reg, size, val);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = dw_pcie_write(base + reg, size, val);
|
||||
if (ret)
|
||||
dev_err(pci->dev, "write DBI address failed\n");
|
||||
}
|
||||
|
||||
static u32 dw_pcie_readl_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg)
|
||||
{
|
||||
u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
|
||||
@ -333,6 +364,17 @@ int dw_pcie_link_up(struct dw_pcie *pci)
|
||||
(!(val & PCIE_PORT_DEBUG1_LINK_IN_TRAINING)));
|
||||
}
|
||||
|
||||
static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT);
|
||||
if (val == 0xffffffff)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dw_pcie_setup(struct dw_pcie *pci)
|
||||
{
|
||||
int ret;
|
||||
@ -341,6 +383,16 @@ void dw_pcie_setup(struct dw_pcie *pci)
|
||||
struct device *dev = pci->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
|
||||
if (pci->version >= 0x480A || (!pci->version &&
|
||||
dw_pcie_iatu_unroll_enabled(pci))) {
|
||||
pci->iatu_unroll_enabled = true;
|
||||
if (!pci->atu_base)
|
||||
pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
|
||||
}
|
||||
dev_dbg(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ?
|
||||
"enabled" : "disabled");
|
||||
|
||||
|
||||
ret = of_property_read_u32(np, "num-lanes", &lanes);
|
||||
if (ret)
|
||||
lanes = 0;
|
||||
|
@ -148,14 +148,9 @@ struct dw_pcie_host_ops {
|
||||
int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
|
||||
unsigned int devfn, int where, int size, u32 val);
|
||||
int (*host_init)(struct pcie_port *pp);
|
||||
void (*msi_set_irq)(struct pcie_port *pp, int irq);
|
||||
void (*msi_clear_irq)(struct pcie_port *pp, int irq);
|
||||
phys_addr_t (*get_msi_addr)(struct pcie_port *pp);
|
||||
u32 (*get_msi_data)(struct pcie_port *pp, int pos);
|
||||
void (*scan_bus)(struct pcie_port *pp);
|
||||
void (*set_num_vectors)(struct pcie_port *pp);
|
||||
int (*msi_host_init)(struct pcie_port *pp);
|
||||
void (*msi_irq_ack)(int irq, struct pcie_port *pp);
|
||||
};
|
||||
|
||||
struct pcie_port {
|
||||
@ -183,6 +178,7 @@ struct pcie_port {
|
||||
struct irq_domain *msi_domain;
|
||||
dma_addr_t msi_data;
|
||||
struct page *msi_page;
|
||||
struct irq_chip *msi_irq_chip;
|
||||
u32 num_vectors;
|
||||
u32 irq_mask[MAX_MSI_CTRLS];
|
||||
struct pci_bus *root_bus;
|
||||
@ -205,7 +201,7 @@ struct dw_pcie_ep_ops {
|
||||
|
||||
struct dw_pcie_ep {
|
||||
struct pci_epc *epc;
|
||||
struct dw_pcie_ep_ops *ops;
|
||||
const struct dw_pcie_ep_ops *ops;
|
||||
phys_addr_t phys_base;
|
||||
size_t addr_size;
|
||||
size_t page_size;
|
||||
@ -227,6 +223,10 @@ struct dw_pcie_ops {
|
||||
size_t size);
|
||||
void (*write_dbi)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
|
||||
size_t size, u32 val);
|
||||
u32 (*read_dbi2)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
|
||||
size_t size);
|
||||
void (*write_dbi2)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
|
||||
size_t size, u32 val);
|
||||
int (*link_up)(struct dw_pcie *pcie);
|
||||
int (*start_link)(struct dw_pcie *pcie);
|
||||
void (*stop_link)(struct dw_pcie *pcie);
|
||||
@ -243,6 +243,7 @@ struct dw_pcie {
|
||||
struct pcie_port pp;
|
||||
struct dw_pcie_ep ep;
|
||||
const struct dw_pcie_ops *ops;
|
||||
unsigned int version;
|
||||
};
|
||||
|
||||
#define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp)
|
||||
@ -257,6 +258,10 @@ u32 __dw_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg,
|
||||
size_t size);
|
||||
void __dw_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg,
|
||||
size_t size, u32 val);
|
||||
u32 __dw_pcie_read_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg,
|
||||
size_t size);
|
||||
void __dw_pcie_write_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg,
|
||||
size_t size, u32 val);
|
||||
int dw_pcie_link_up(struct dw_pcie *pci);
|
||||
int dw_pcie_wait_for_link(struct dw_pcie *pci);
|
||||
void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
|
||||
@ -300,12 +305,12 @@ static inline u8 dw_pcie_readb_dbi(struct dw_pcie *pci, u32 reg)
|
||||
|
||||
static inline void dw_pcie_writel_dbi2(struct dw_pcie *pci, u32 reg, u32 val)
|
||||
{
|
||||
__dw_pcie_write_dbi(pci, pci->dbi_base2, reg, 0x4, val);
|
||||
__dw_pcie_write_dbi2(pci, pci->dbi_base2, reg, 0x4, val);
|
||||
}
|
||||
|
||||
static inline u32 dw_pcie_readl_dbi2(struct dw_pcie *pci, u32 reg)
|
||||
{
|
||||
return __dw_pcie_read_dbi(pci, pci->dbi_base2, reg, 0x4);
|
||||
return __dw_pcie_read_dbi2(pci, pci->dbi_base2, reg, 0x4);
|
||||
}
|
||||
|
||||
static inline void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val)
|
||||
|
@ -438,7 +438,7 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
|
||||
epc_features = epf_test->epc_features;
|
||||
|
||||
base = pci_epf_alloc_space(epf, sizeof(struct pci_epf_test_reg),
|
||||
test_reg_bar);
|
||||
test_reg_bar, epc_features->align);
|
||||
if (!base) {
|
||||
dev_err(dev, "Failed to allocated register space\n");
|
||||
return -ENOMEM;
|
||||
@ -453,7 +453,8 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
|
||||
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,
|
||||
epc_features->align);
|
||||
if (!base)
|
||||
dev_err(dev, "Failed to allocate space for BAR%d\n",
|
||||
bar);
|
||||
|
@ -109,10 +109,12 @@ EXPORT_SYMBOL_GPL(pci_epf_free_space);
|
||||
* pci_epf_alloc_space() - allocate memory for the PCI EPF register space
|
||||
* @size: the size of the memory that has to be allocated
|
||||
* @bar: the BAR number corresponding to the allocated register space
|
||||
* @align: alignment size for the allocation region
|
||||
*
|
||||
* Invoke to allocate memory for the PCI EPF register space.
|
||||
*/
|
||||
void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar)
|
||||
void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
|
||||
size_t align)
|
||||
{
|
||||
void *space;
|
||||
struct device *dev = epf->epc->dev.parent;
|
||||
@ -120,7 +122,11 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar)
|
||||
|
||||
if (size < 128)
|
||||
size = 128;
|
||||
size = roundup_pow_of_two(size);
|
||||
|
||||
if (align)
|
||||
size = ALIGN(size, align);
|
||||
else
|
||||
size = roundup_pow_of_two(size);
|
||||
|
||||
space = dma_alloc_coherent(dev, size, &phys_addr, GFP_KERNEL);
|
||||
if (!space) {
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/of_pci.h>
|
||||
#include "pci.h"
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
void pci_set_of_node(struct pci_dev *dev)
|
||||
{
|
||||
if (!dev->bus->dev.of_node)
|
||||
@ -202,27 +203,6 @@ int of_get_pci_domain_nr(struct device_node *node)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_get_pci_domain_nr);
|
||||
|
||||
/**
|
||||
* This function will try to find the limitation of link speed by finding
|
||||
* a property called "max-link-speed" of the given device node.
|
||||
*
|
||||
* @node: device tree node with the max link speed information
|
||||
*
|
||||
* Returns the associated max link speed from DT, or a negative value if the
|
||||
* required property is not found or is invalid.
|
||||
*/
|
||||
int of_pci_get_max_link_speed(struct device_node *node)
|
||||
{
|
||||
u32 max_link_speed;
|
||||
|
||||
if (of_property_read_u32(node, "max-link-speed", &max_link_speed) ||
|
||||
max_link_speed > 4)
|
||||
return -EINVAL;
|
||||
|
||||
return max_link_speed;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_pci_get_max_link_speed);
|
||||
|
||||
/**
|
||||
* of_pci_check_probe_only - Setup probe only mode if linux,pci-probe-only
|
||||
* is present and valid
|
||||
@ -543,3 +523,25 @@ int pci_parse_request_of_pci_ranges(struct device *dev,
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PCI */
|
||||
|
||||
/**
|
||||
* This function will try to find the limitation of link speed by finding
|
||||
* a property called "max-link-speed" of the given device node.
|
||||
*
|
||||
* @node: device tree node with the max link speed information
|
||||
*
|
||||
* Returns the associated max link speed from DT, or a negative value if the
|
||||
* required property is not found or is invalid.
|
||||
*/
|
||||
int of_pci_get_max_link_speed(struct device_node *node)
|
||||
{
|
||||
u32 max_link_speed;
|
||||
|
||||
if (of_property_read_u32(node, "max-link-speed", &max_link_speed) ||
|
||||
max_link_speed > 4)
|
||||
return -EINVAL;
|
||||
|
||||
return max_link_speed;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_pci_get_max_link_speed);
|
||||
|
@ -109,6 +109,7 @@ struct pci_epc {
|
||||
* @reserved_bar: bitmap to indicate reserved BAR unavailable to function driver
|
||||
* @bar_fixed_64bit: bitmap to indicate fixed 64bit BARs
|
||||
* @bar_fixed_size: Array specifying the size supported by each BAR
|
||||
* @align: alignment size required for BAR buffer allocation
|
||||
*/
|
||||
struct pci_epc_features {
|
||||
unsigned int linkup_notifier : 1;
|
||||
@ -117,6 +118,7 @@ struct pci_epc_features {
|
||||
u8 reserved_bar;
|
||||
u8 bar_fixed_64bit;
|
||||
u64 bar_fixed_size[BAR_5 + 1];
|
||||
size_t align;
|
||||
};
|
||||
|
||||
#define to_pci_epc(device) container_of((device), struct pci_epc, dev)
|
||||
|
@ -149,7 +149,8 @@ void pci_epf_destroy(struct pci_epf *epf);
|
||||
int __pci_epf_register_driver(struct pci_epf_driver *driver,
|
||||
struct module *owner);
|
||||
void pci_epf_unregister_driver(struct pci_epf_driver *driver);
|
||||
void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar);
|
||||
void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
|
||||
size_t align);
|
||||
void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar);
|
||||
int pci_epf_bind(struct pci_epf *epf);
|
||||
void pci_epf_unbind(struct pci_epf *epf);
|
||||
|
Loading…
x
Reference in New Issue
Block a user