Commit 0f74d898 authored by Bjorn Helgaas's avatar Bjorn Helgaas

Merge branch 'pci/endpoint'

- Remove unused struct pci_epf_group.type_group (Christophe JAILLET)

- Use cached epc_features instead of pci_epc_get_features() to avoid having
  to check for failure (potential NULL pointer dereference) (Manivannan
  Sadhasivam)

- Drop pointless local msix_capable variable in pci_epf_test_alloc_space()
  (Manivannan Sadhasivam)

- Rename struct pci_epc_event_ops.core_init to .epc_init, since "core" is
  no longer meaningful here (Manivannan Sadhasivam)

- Rename pci_epc_bme_notify(), pci_epf_mhi_bme(), pci_epc_bme_notify() to
  spell out "bus_master_enable" instead of "bme" (Manivannan Sadhasivam)

- Factor pci_epf_test_clear_bar() and pci_epf_test_free_space() out of
  pci_epf_test_unbind() so they can be reused elsewhere (Manivannan
  Sadhasivam)

- Move DMA initialization to the pci_epf_mhi_epc_init() callback so
  endpoint drivers do this uniformly (Manivannan Sadhasivam)

- Add endpoint testing for Link Down events (Manivannan Sadhasivam)

- Add 'epc_deinit' event so endpoints that can be reset via PERST# (qcom,
  tegra194) can notify EPF drivers when this happens (Manivannan
  Sadhasivam)

- Make pci_epc_class constant (Greg Kroah-Hartman)

- Fix vpci_scan_bus() error checking to print error for failure (not
  success) and clean up after failure (Dan Carpenter)

- Fix epf_ntb_epc_cleanup() error handling to clean up scratchpad BARs and
  clean up in mirror order of allocation (Dan Carpenter)

- Add rk3588, which requires 64KB BAR alignment, to pci_endpoint_test
  (Niklas Cassel)

- Use memcpy_toio()/memcpy_fromio() for endpoint BAR tests to improve
  performance (Niklas Cassel)

- Set DMA mask to 48 bits always to simplify endpoint test, since there's
  there's no need to check for error or to fallback to 32 bits (Frank Li)

- Suggest using programmable Vendor/Device ID (when supported) to use
  pci_endpoint_test without having to add new entries (Yoshihiro Shimoda)

- Remove unused pci_endpoint_test_bar_{readl,writel}() (Jiapeng Chong)

- Remove 'linkup' and add 'add_cfs' to the endpoint function driver 'ops'
  documentation to match the code (Alexander Stein)

-

* pci/endpoint:
  Documentation: PCI: pci-endpoint: Fix EPF ops list
  misc: pci_endpoint_test: Remove unused pci_endpoint_test_bar_{readl,writel} functions
  misc: pci_endpoint_test: Document policy about adding pci_device_id
  misc: pci_endpoint_test: Refactor dma_set_mask_and_coherent() logic
  misc: pci_endpoint_test: Use memcpy_toio()/memcpy_fromio() for BAR tests
  misc: pci_endpoint_test: Add support for Rockchip rk3588
  PCI: endpoint: Fix error handling in epf_ntb_epc_cleanup()
  PCI: endpoint: Clean up error handling in vpci_scan_bus()
  PCI: endpoint: Make pci_epc_class struct constant
  PCI: endpoint: Introduce 'epc_deinit' event and notify the EPF drivers
  PCI: endpoint: pci-epf-test: Handle Link Down event
  PCI: endpoint: pci-epf-{mhi/test}: Move DMA initialization to EPC init callback
  PCI: endpoint: pci-epf-test: Refactor pci_epf_test_unbind() function
  PCI: endpoint: Rename BME to Bus Master Enable
  PCI: endpoint: Rename core_init() callback in 'struct pci_epc_event_ops' to epc_init()
  PCI: endpoint: pci-epf-test: Use 'msix_capable' flag directly in pci_epf_test_alloc_space()
  PCI: endpoint: pci-epf-test: Make use of cached 'epc_features' in pci_epf_test_core_init()
  PCI: endpoint: Remove unused field in struct pci_epf_group
parents 7095d21e 96447ede
......@@ -172,8 +172,8 @@ by the PCI endpoint function driver.
* bind: ops to perform when a EPC device has been bound to EPF device
* unbind: ops to perform when a binding has been lost between a EPC
device and EPF device
* linkup: ops to perform when the EPC device has established a
connection with a host system
* add_cfs: optional ops to create function specific configfs
attributes
The PCI Function driver can then register the PCI EPF driver by using
pci_epf_register_driver().
......
......@@ -7,6 +7,7 @@
*/
#include <linux/crc32.h>
#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/io.h>
......@@ -84,6 +85,9 @@
#define PCI_DEVICE_ID_RENESAS_R8A774E1 0x0025
#define PCI_DEVICE_ID_RENESAS_R8A779F0 0x0031
#define PCI_VENDOR_ID_ROCKCHIP 0x1d87
#define PCI_DEVICE_ID_ROCKCHIP_RK3588 0x3588
static DEFINE_IDA(pci_endpoint_test_ida);
#define to_endpoint_test(priv) container_of((priv), struct pci_endpoint_test, \
......@@ -140,18 +144,6 @@ static inline void pci_endpoint_test_writel(struct pci_endpoint_test *test,
writel(value, test->base + offset);
}
static inline u32 pci_endpoint_test_bar_readl(struct pci_endpoint_test *test,
int bar, int offset)
{
return readl(test->bar[bar] + offset);
}
static inline void pci_endpoint_test_bar_writel(struct pci_endpoint_test *test,
int bar, u32 offset, u32 value)
{
writel(value, test->bar[bar] + offset);
}
static irqreturn_t pci_endpoint_test_irqhandler(int irq, void *dev_id)
{
struct pci_endpoint_test *test = dev_id;
......@@ -272,31 +264,60 @@ static const u32 bar_test_pattern[] = {
0xA5A5A5A5,
};
static int pci_endpoint_test_bar_memcmp(struct pci_endpoint_test *test,
enum pci_barno barno, int offset,
void *write_buf, void *read_buf,
int size)
{
memset(write_buf, bar_test_pattern[barno], size);
memcpy_toio(test->bar[barno] + offset, write_buf, size);
memcpy_fromio(read_buf, test->bar[barno] + offset, size);
return memcmp(write_buf, read_buf, size);
}
static bool pci_endpoint_test_bar(struct pci_endpoint_test *test,
enum pci_barno barno)
{
int j;
u32 val;
int size;
int j, bar_size, buf_size, iters, remain;
void *write_buf __free(kfree) = NULL;
void *read_buf __free(kfree) = NULL;
struct pci_dev *pdev = test->pdev;
if (!test->bar[barno])
return false;
size = pci_resource_len(pdev, barno);
bar_size = pci_resource_len(pdev, barno);
if (barno == test->test_reg_bar)
size = 0x4;
bar_size = 0x4;
/*
* Allocate a buffer of max size 1MB, and reuse that buffer while
* iterating over the whole BAR size (which might be much larger).
*/
buf_size = min(SZ_1M, bar_size);
for (j = 0; j < size; j += 4)
pci_endpoint_test_bar_writel(test, barno, j,
bar_test_pattern[barno]);
write_buf = kmalloc(buf_size, GFP_KERNEL);
if (!write_buf)
return false;
for (j = 0; j < size; j += 4) {
val = pci_endpoint_test_bar_readl(test, barno, j);
if (val != bar_test_pattern[barno])
read_buf = kmalloc(buf_size, GFP_KERNEL);
if (!read_buf)
return false;
iters = bar_size / buf_size;
for (j = 0; j < iters; j++)
if (pci_endpoint_test_bar_memcmp(test, barno, buf_size * j,
write_buf, read_buf, buf_size))
return false;
remain = bar_size % buf_size;
if (remain)
if (pci_endpoint_test_bar_memcmp(test, barno, buf_size * iters,
write_buf, read_buf, remain))
return false;
}
return true;
}
......@@ -824,11 +845,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
init_completion(&test->irq_raised);
mutex_init(&test->mutex);
if ((dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48)) != 0) &&
dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)) != 0) {
dev_err(dev, "Cannot set DMA mask\n");
return -EINVAL;
}
dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48));
err = pci_enable_device(pdev);
if (err) {
......@@ -980,6 +997,15 @@ static const struct pci_endpoint_test_data j721e_data = {
.irq_type = IRQ_TYPE_MSI,
};
static const struct pci_endpoint_test_data rk3588_data = {
.alignment = SZ_64K,
.irq_type = IRQ_TYPE_MSI,
};
/*
* If the controller's Vendor/Device ID are programmable, you may be able to
* use one of the existing entries for testing instead of adding a new one.
*/
static const struct pci_device_id pci_endpoint_test_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x),
.driver_data = (kernel_ulong_t)&default_data,
......@@ -1017,6 +1043,9 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721S2),
.driver_data = (kernel_ulong_t)&j721e_data,
},
{ PCI_DEVICE(PCI_VENDOR_ID_ROCKCHIP, PCI_DEVICE_ID_ROCKCHIP_RK3588),
.driver_data = (kernel_ulong_t)&rk3588_data,
},
{ }
};
MODULE_DEVICE_TABLE(pci, pci_endpoint_test_tbl);
......
......@@ -632,7 +632,6 @@ void dw_pcie_ep_cleanup(struct dw_pcie_ep *ep)
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
dw_pcie_edma_remove(pci);
ep->epc->init_complete = false;
}
EXPORT_SYMBOL_GPL(dw_pcie_ep_cleanup);
......
......@@ -507,6 +507,7 @@ static void qcom_pcie_perst_assert(struct dw_pcie *pci)
return;
}
pci_epc_deinit_notify(pci->ep.epc);
dw_pcie_ep_cleanup(&pci->ep);
qcom_pcie_disable_resources(pcie_ep);
pcie_ep->link_status = QCOM_PCIE_EP_LINK_DISABLED;
......@@ -642,10 +643,10 @@ static irqreturn_t qcom_pcie_ep_global_irq_thread(int irq, void *data)
pcie_ep->link_status = QCOM_PCIE_EP_LINK_DOWN;
pci_epc_linkdown(pci->ep.epc);
} else if (FIELD_GET(PARF_INT_ALL_BME, status)) {
dev_dbg(dev, "Received BME event. Link is enabled!\n");
dev_dbg(dev, "Received Bus Master Enable event\n");
pcie_ep->link_status = QCOM_PCIE_EP_LINK_ENABLED;
qcom_pcie_ep_icc_update(pcie_ep);
pci_epc_bme_notify(pci->ep.epc);
pci_epc_bus_master_enable_notify(pci->ep.epc);
} else if (FIELD_GET(PARF_INT_ALL_PM_TURNOFF, status)) {
dev_dbg(dev, "Received PM Turn-off event! Entering L23\n");
val = readl_relaxed(pcie_ep->parf + PARF_PM_CTRL);
......
......@@ -1715,6 +1715,7 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie)
if (ret)
dev_err(pcie->dev, "Failed to go Detect state: %d\n", ret);
pci_epc_deinit_notify(pcie->pci.ep.epc);
dw_pcie_ep_cleanup(&pcie->pci.ep);
reset_control_assert(pcie->core_rst);
......
......@@ -716,7 +716,7 @@ static void pci_epf_mhi_dma_deinit(struct pci_epf_mhi *epf_mhi)
epf_mhi->dma_chan_rx = NULL;
}
static int pci_epf_mhi_core_init(struct pci_epf *epf)
static int pci_epf_mhi_epc_init(struct pci_epf *epf)
{
struct pci_epf_mhi *epf_mhi = epf_get_drvdata(epf);
const struct pci_epf_mhi_ep_info *info = epf_mhi->info;
......@@ -753,9 +753,35 @@ static int pci_epf_mhi_core_init(struct pci_epf *epf)
if (!epf_mhi->epc_features)
return -ENODATA;
if (info->flags & MHI_EPF_USE_DMA) {
ret = pci_epf_mhi_dma_init(epf_mhi);
if (ret) {
dev_err(dev, "Failed to initialize DMA: %d\n", ret);
return ret;
}
}
return 0;
}
static void pci_epf_mhi_epc_deinit(struct pci_epf *epf)
{
struct pci_epf_mhi *epf_mhi = epf_get_drvdata(epf);
const struct pci_epf_mhi_ep_info *info = epf_mhi->info;
struct pci_epf_bar *epf_bar = &epf->bar[info->bar_num];
struct mhi_ep_cntrl *mhi_cntrl = &epf_mhi->mhi_cntrl;
struct pci_epc *epc = epf->epc;
if (mhi_cntrl->mhi_dev) {
mhi_ep_power_down(mhi_cntrl);
if (info->flags & MHI_EPF_USE_DMA)
pci_epf_mhi_dma_deinit(epf_mhi);
mhi_ep_unregister_controller(mhi_cntrl);
}
pci_epc_clear_bar(epc, epf->func_no, epf->vfunc_no, epf_bar);
}
static int pci_epf_mhi_link_up(struct pci_epf *epf)
{
struct pci_epf_mhi *epf_mhi = epf_get_drvdata(epf);
......@@ -765,14 +791,6 @@ static int pci_epf_mhi_link_up(struct pci_epf *epf)
struct device *dev = &epf->dev;
int ret;
if (info->flags & MHI_EPF_USE_DMA) {
ret = pci_epf_mhi_dma_init(epf_mhi);
if (ret) {
dev_err(dev, "Failed to initialize DMA: %d\n", ret);
return ret;
}
}
mhi_cntrl->mmio = epf_mhi->mmio;
mhi_cntrl->irq = epf_mhi->irq;
mhi_cntrl->mru = info->mru;
......@@ -819,7 +837,7 @@ static int pci_epf_mhi_link_down(struct pci_epf *epf)
return 0;
}
static int pci_epf_mhi_bme(struct pci_epf *epf)
static int pci_epf_mhi_bus_master_enable(struct pci_epf *epf)
{
struct pci_epf_mhi *epf_mhi = epf_get_drvdata(epf);
const struct pci_epf_mhi_ep_info *info = epf_mhi->info;
......@@ -882,8 +900,8 @@ static void pci_epf_mhi_unbind(struct pci_epf *epf)
/*
* Forcefully power down the MHI EP stack. Only way to bring the MHI EP
* stack back to working state after successive bind is by getting BME
* from host.
* stack back to working state after successive bind is by getting Bus
* Master Enable event from host.
*/
if (mhi_cntrl->mhi_dev) {
mhi_ep_power_down(mhi_cntrl);
......@@ -897,10 +915,11 @@ static void pci_epf_mhi_unbind(struct pci_epf *epf)
}
static const struct pci_epc_event_ops pci_epf_mhi_event_ops = {
.core_init = pci_epf_mhi_core_init,
.epc_init = pci_epf_mhi_epc_init,
.epc_deinit = pci_epf_mhi_epc_deinit,
.link_up = pci_epf_mhi_link_up,
.link_down = pci_epf_mhi_link_down,
.bme = pci_epf_mhi_bme,
.bus_master_enable = pci_epf_mhi_bus_master_enable,
};
static int pci_epf_mhi_probe(struct pci_epf *epf,
......
......@@ -686,25 +686,6 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
msecs_to_jiffies(1));
}
static void pci_epf_test_unbind(struct pci_epf *epf)
{
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
struct pci_epc *epc = epf->epc;
int bar;
cancel_delayed_work(&epf_test->cmd_handler);
pci_epf_test_clean_dma_chan(epf_test);
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
if (!epf_test->reg[bar])
continue;
pci_epc_clear_bar(epc, epf->func_no, epf->vfunc_no,
&epf->bar[bar]);
pci_epf_free_space(epf, epf_test->reg[bar], bar,
PRIMARY_INTERFACE);
}
}
static int pci_epf_test_set_bar(struct pci_epf *epf)
{
int bar, ret;
......@@ -731,23 +712,36 @@ static int pci_epf_test_set_bar(struct pci_epf *epf)
return 0;
}
static int pci_epf_test_core_init(struct pci_epf *epf)
static void pci_epf_test_clear_bar(struct pci_epf *epf)
{
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
struct pci_epc *epc = epf->epc;
int bar;
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
if (!epf_test->reg[bar])
continue;
pci_epc_clear_bar(epc, epf->func_no, epf->vfunc_no,
&epf->bar[bar]);
}
}
static int pci_epf_test_epc_init(struct pci_epf *epf)
{
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
struct pci_epf_header *header = epf->header;
const struct pci_epc_features *epc_features;
const struct pci_epc_features *epc_features = epf_test->epc_features;
struct pci_epc *epc = epf->epc;
struct device *dev = &epf->dev;
bool linkup_notifier = false;
bool msix_capable = false;
bool msi_capable = true;
int ret;
epc_features = pci_epc_get_features(epc, epf->func_no, epf->vfunc_no);
if (epc_features) {
msix_capable = epc_features->msix_capable;
msi_capable = epc_features->msi_capable;
}
epf_test->dma_supported = true;
ret = pci_epf_test_init_dma_chan(epf_test);
if (ret)
epf_test->dma_supported = false;
if (epf->vfunc_no <= 1) {
ret = pci_epc_write_header(epc, epf->func_no, epf->vfunc_no, header);
......@@ -761,7 +755,7 @@ static int pci_epf_test_core_init(struct pci_epf *epf)
if (ret)
return ret;
if (msi_capable) {
if (epc_features->msi_capable) {
ret = pci_epc_set_msi(epc, epf->func_no, epf->vfunc_no,
epf->msi_interrupts);
if (ret) {
......@@ -770,7 +764,7 @@ static int pci_epf_test_core_init(struct pci_epf *epf)
}
}
if (msix_capable) {
if (epc_features->msix_capable) {
ret = pci_epc_set_msix(epc, epf->func_no, epf->vfunc_no,
epf->msix_interrupts,
epf_test->test_reg_bar,
......@@ -788,6 +782,15 @@ static int pci_epf_test_core_init(struct pci_epf *epf)
return 0;
}
static void pci_epf_test_epc_deinit(struct pci_epf *epf)
{
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
cancel_delayed_work(&epf_test->cmd_handler);
pci_epf_test_clean_dma_chan(epf_test);
pci_epf_test_clear_bar(epf);
}
static int pci_epf_test_link_up(struct pci_epf *epf)
{
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
......@@ -798,9 +801,20 @@ static int pci_epf_test_link_up(struct pci_epf *epf)
return 0;
}
static int pci_epf_test_link_down(struct pci_epf *epf)
{
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
cancel_delayed_work_sync(&epf_test->cmd_handler);
return 0;
}
static const struct pci_epc_event_ops pci_epf_test_event_ops = {
.core_init = pci_epf_test_core_init,
.epc_init = pci_epf_test_epc_init,
.epc_deinit = pci_epf_test_epc_deinit,
.link_up = pci_epf_test_link_up,
.link_down = pci_epf_test_link_down,
};
static int pci_epf_test_alloc_space(struct pci_epf *epf)
......@@ -810,19 +824,15 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
size_t msix_table_size = 0;
size_t test_reg_bar_size;
size_t pba_size = 0;
bool msix_capable;
void *base;
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
enum pci_barno bar;
const struct pci_epc_features *epc_features;
const struct pci_epc_features *epc_features = epf_test->epc_features;
size_t test_reg_size;
epc_features = epf_test->epc_features;
test_reg_bar_size = ALIGN(sizeof(struct pci_epf_test_reg), 128);
msix_capable = epc_features->msix_capable;
if (msix_capable) {
if (epc_features->msix_capable) {
msix_table_size = PCI_MSIX_ENTRY_SIZE * epf->msix_interrupts;
epf_test->msix_table_offset = test_reg_bar_size;
/* Align to QWORD or 8 Bytes */
......@@ -857,6 +867,20 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
return 0;
}
static void pci_epf_test_free_space(struct pci_epf *epf)
{
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
int bar;
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
if (!epf_test->reg[bar])
continue;
pci_epf_free_space(epf, epf_test->reg[bar], bar,
PRIMARY_INTERFACE);
}
}
static int pci_epf_test_bind(struct pci_epf *epf)
{
int ret;
......@@ -885,13 +909,20 @@ static int pci_epf_test_bind(struct pci_epf *epf)
if (ret)
return ret;
epf_test->dma_supported = true;
return 0;
}
ret = pci_epf_test_init_dma_chan(epf_test);
if (ret)
epf_test->dma_supported = false;
static void pci_epf_test_unbind(struct pci_epf *epf)
{
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
struct pci_epc *epc = epf->epc;
return 0;
cancel_delayed_work(&epf_test->cmd_handler);
if (epc->init_complete) {
pci_epf_test_clean_dma_chan(epf_test);
pci_epf_test_clear_bar(epf);
}
pci_epf_test_free_space(epf);
}
static const struct pci_epf_device_id pci_epf_test_ids[] = {
......
......@@ -799,8 +799,9 @@ static int epf_ntb_epc_init(struct epf_ntb *ntb)
*/
static void epf_ntb_epc_cleanup(struct epf_ntb *ntb)
{
epf_ntb_db_bar_clear(ntb);
epf_ntb_mw_bar_clear(ntb, ntb->num_mws);
epf_ntb_db_bar_clear(ntb);
epf_ntb_config_sspad_bar_clear(ntb);
}
#define EPF_NTB_R(_name) \
......@@ -1018,8 +1019,10 @@ static int vpci_scan_bus(void *sysdata)
struct epf_ntb *ndev = sysdata;
vpci_bus = pci_scan_bus(ndev->vbus_number, &vpci_ops, sysdata);
if (vpci_bus)
pr_err("create pci bus\n");
if (!vpci_bus) {
pr_err("create pci bus failed\n");
return -EINVAL;
}
pci_bus_add_devices(vpci_bus);
......@@ -1335,13 +1338,19 @@ static int epf_ntb_bind(struct pci_epf *epf)
ret = pci_register_driver(&vntb_pci_driver);
if (ret) {
dev_err(dev, "failure register vntb pci driver\n");
goto err_bar_alloc;
goto err_epc_cleanup;
}
vpci_scan_bus(ntb);
ret = vpci_scan_bus(ntb);
if (ret)
goto err_unregister;
return 0;
err_unregister:
pci_unregister_driver(&vntb_pci_driver);
err_epc_cleanup:
epf_ntb_epc_cleanup(ntb);
err_bar_alloc:
epf_ntb_config_spad_bar_free(ntb);
......
......@@ -23,7 +23,6 @@ struct pci_epf_group {
struct config_group group;
struct config_group primary_epc_group;
struct config_group secondary_epc_group;
struct config_group *type_group;
struct delayed_work cfs_work;
struct pci_epf *epf;
int index;
......
......@@ -14,7 +14,9 @@
#include <linux/pci-epf.h>
#include <linux/pci-ep-cfs.h>
static struct class *pci_epc_class;
static const struct class pci_epc_class = {
.name = "pci_epc",
};
static void devm_pci_epc_release(struct device *dev, void *res)
{
......@@ -60,7 +62,7 @@ struct pci_epc *pci_epc_get(const char *epc_name)
struct device *dev;
struct class_dev_iter iter;
class_dev_iter_init(&iter, pci_epc_class, NULL, NULL);
class_dev_iter_init(&iter, &pci_epc_class, NULL, NULL);
while ((dev = class_dev_iter_next(&iter))) {
if (strcmp(epc_name, dev_name(dev)))
continue;
......@@ -727,9 +729,9 @@ void pci_epc_linkdown(struct pci_epc *epc)
EXPORT_SYMBOL_GPL(pci_epc_linkdown);
/**
* pci_epc_init_notify() - Notify the EPF device that EPC device's core
* initialization is completed.
* @epc: the EPC device whose core initialization is completed
* pci_epc_init_notify() - Notify the EPF device that EPC device initialization
* is completed.
* @epc: the EPC device whose initialization is completed
*
* Invoke to Notify the EPF device that the EPC device's initialization
* is completed.
......@@ -744,8 +746,8 @@ void pci_epc_init_notify(struct pci_epc *epc)
mutex_lock(&epc->list_lock);
list_for_each_entry(epf, &epc->pci_epf, list) {
mutex_lock(&epf->lock);
if (epf->event_ops && epf->event_ops->core_init)
epf->event_ops->core_init(epf);
if (epf->event_ops && epf->event_ops->epc_init)
epf->event_ops->epc_init(epf);
mutex_unlock(&epf->lock);
}
epc->init_complete = true;
......@@ -756,7 +758,7 @@ EXPORT_SYMBOL_GPL(pci_epc_init_notify);
/**
* pci_epc_notify_pending_init() - Notify the pending EPC device initialization
* complete to the EPF device
* @epc: the EPC device whose core initialization is pending to be notified
* @epc: the EPC device whose initialization is pending to be notified
* @epf: the EPF device to be notified
*
* Invoke to notify the pending EPC device initialization complete to the EPF
......@@ -767,22 +769,20 @@ void pci_epc_notify_pending_init(struct pci_epc *epc, struct pci_epf *epf)
{
if (epc->init_complete) {
mutex_lock(&epf->lock);
if (epf->event_ops && epf->event_ops->core_init)
epf->event_ops->core_init(epf);
if (epf->event_ops && epf->event_ops->epc_init)
epf->event_ops->epc_init(epf);
mutex_unlock(&epf->lock);
}
}
EXPORT_SYMBOL_GPL(pci_epc_notify_pending_init);
/**
* pci_epc_bme_notify() - Notify the EPF device that the EPC device has received
* the BME event from the Root complex
* @epc: the EPC device that received the BME event
* pci_epc_deinit_notify() - Notify the EPF device about EPC deinitialization
* @epc: the EPC device whose deinitialization is completed
*
* Invoke to Notify the EPF device that the EPC device has received the Bus
* Master Enable (BME) event from the Root complex
* Invoke to notify the EPF device that the EPC deinitialization is completed.
*/
void pci_epc_bme_notify(struct pci_epc *epc)
void pci_epc_deinit_notify(struct pci_epc *epc)
{
struct pci_epf *epf;
......@@ -792,13 +792,41 @@ void pci_epc_bme_notify(struct pci_epc *epc)
mutex_lock(&epc->list_lock);
list_for_each_entry(epf, &epc->pci_epf, list) {
mutex_lock(&epf->lock);
if (epf->event_ops && epf->event_ops->bme)
epf->event_ops->bme(epf);
if (epf->event_ops && epf->event_ops->epc_deinit)
epf->event_ops->epc_deinit(epf);
mutex_unlock(&epf->lock);
}
epc->init_complete = false;
mutex_unlock(&epc->list_lock);
}
EXPORT_SYMBOL_GPL(pci_epc_bme_notify);
EXPORT_SYMBOL_GPL(pci_epc_deinit_notify);
/**
* pci_epc_bus_master_enable_notify() - Notify the EPF device that the EPC
* device has received the Bus Master
* Enable event from the Root complex
* @epc: the EPC device that received the Bus Master Enable event
*
* Notify the EPF device that the EPC device has generated the Bus Master Enable
* event due to host setting the Bus Master Enable bit in the Command register.
*/
void pci_epc_bus_master_enable_notify(struct pci_epc *epc)
{
struct pci_epf *epf;
if (IS_ERR_OR_NULL(epc))
return;
mutex_lock(&epc->list_lock);
list_for_each_entry(epf, &epc->pci_epf, list) {
mutex_lock(&epf->lock);
if (epf->event_ops && epf->event_ops->bus_master_enable)
epf->event_ops->bus_master_enable(epf);
mutex_unlock(&epf->lock);
}
mutex_unlock(&epc->list_lock);
}
EXPORT_SYMBOL_GPL(pci_epc_bus_master_enable_notify);
/**
* pci_epc_destroy() - destroy the EPC device
......@@ -867,7 +895,7 @@ __pci_epc_create(struct device *dev, const struct pci_epc_ops *ops,
INIT_LIST_HEAD(&epc->pci_epf);
device_initialize(&epc->dev);
epc->dev.class = pci_epc_class;
epc->dev.class = &pci_epc_class;
epc->dev.parent = dev;
epc->dev.release = pci_epc_release;
epc->ops = ops;
......@@ -927,20 +955,13 @@ EXPORT_SYMBOL_GPL(__devm_pci_epc_create);
static int __init pci_epc_init(void)
{
pci_epc_class = class_create("pci_epc");
if (IS_ERR(pci_epc_class)) {
pr_err("failed to create pci epc class --> %ld\n",
PTR_ERR(pci_epc_class));
return PTR_ERR(pci_epc_class);
}
return 0;
return class_register(&pci_epc_class);
}
module_init(pci_epc_init);
static void __exit pci_epc_exit(void)
{
class_destroy(pci_epc_class);
class_unregister(&pci_epc_class);
}
module_exit(pci_epc_exit);
......
......@@ -197,6 +197,8 @@ struct pci_epc_features {
#define to_pci_epc(device) container_of((device), struct pci_epc, dev)
#ifdef CONFIG_PCI_ENDPOINT
#define pci_epc_create(dev, ops) \
__pci_epc_create((dev), (ops), THIS_MODULE)
#define devm_pci_epc_create(dev, ops) \
......@@ -226,7 +228,8 @@ void pci_epc_linkup(struct pci_epc *epc);
void pci_epc_linkdown(struct pci_epc *epc);
void pci_epc_init_notify(struct pci_epc *epc);
void pci_epc_notify_pending_init(struct pci_epc *epc, struct pci_epf *epf);
void pci_epc_bme_notify(struct pci_epc *epc);
void pci_epc_deinit_notify(struct pci_epc *epc);
void pci_epc_bus_master_enable_notify(struct pci_epc *epc);
void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf,
enum pci_epc_interface_type type);
int pci_epc_write_header(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
......@@ -272,4 +275,14 @@ void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc,
phys_addr_t *phys_addr, size_t size);
void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr,
void __iomem *virt_addr, size_t size);
#else
static inline void pci_epc_init_notify(struct pci_epc *epc)
{
}
static inline void pci_epc_deinit_notify(struct pci_epc *epc)
{
}
#endif /* CONFIG_PCI_ENDPOINT */
#endif /* __LINUX_PCI_EPC_H */
......@@ -70,16 +70,18 @@ struct pci_epf_ops {
/**
* struct pci_epc_event_ops - Callbacks for capturing the EPC events
* @core_init: Callback for the EPC initialization complete event
* @epc_init: Callback for the EPC initialization complete event
* @epc_deinit: Callback for the EPC deinitialization event
* @link_up: Callback for the EPC link up event
* @link_down: Callback for the EPC link down event
* @bme: Callback for the EPC BME (Bus Master Enable) event
* @bus_master_enable: Callback for the EPC Bus Master Enable event
*/
struct pci_epc_event_ops {
int (*core_init)(struct pci_epf *epf);
int (*epc_init)(struct pci_epf *epf);
void (*epc_deinit)(struct pci_epf *epf);
int (*link_up)(struct pci_epf *epf);
int (*link_down)(struct pci_epf *epf);
int (*bme)(struct pci_epf *epf);
int (*bus_master_enable)(struct pci_epf *epf);
};
/**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment