Merge branch 'pci/endpoint'

- Convert dra7xx to threaded IRQ handler (Manivannan Sadhasivam)

- Move tegra194 dw_pcie_ep_linkup() to threaded IRQ handler (Manivannan
  Sadhasivam)

- Add a separate lock for the endpoint pci_epf list to avoid deadlock
  while running callbacks (Manivannan Sadhasivam)

- Use callbacks instead of notifier chains to signal events from EPC to EPF
  drivers (Manivannan Sadhasivam)

- Use link_up() callback in place of LINK_UP notifier (Manivannan
  Sadhasivam)

* pci/endpoint:
  PCI: endpoint: Use link_up() callback in place of LINK_UP notifier
  PCI: endpoint: Use callback mechanism for passing events from EPC to EPF
  PCI: endpoint: Use a separate lock for protecting epc->pci_epf list
  PCI: tegra194: Move dw_pcie_ep_linkup() to threaded IRQ handler
  PCI: dra7xx: Use threaded IRQ handler for "dra7xx-pcie-main" IRQ
This commit is contained in:
Bjorn Helgaas 2023-02-22 13:47:28 -06:00
commit 33abd97c34
6 changed files with 59 additions and 51 deletions

View File

@ -840,7 +840,7 @@ static int dra7xx_pcie_probe(struct platform_device *pdev)
}
dra7xx->mode = mode;
ret = devm_request_irq(dev, irq, dra7xx_pcie_irq_handler,
ret = devm_request_threaded_irq(dev, irq, NULL, dra7xx_pcie_irq_handler,
IRQF_SHARED, "dra7xx-pcie-main", dra7xx);
if (ret) {
dev_err(dev, "failed to request irq\n");

View File

@ -286,6 +286,7 @@ struct tegra_pcie_dw {
struct gpio_desc *pex_refclk_sel_gpiod;
unsigned int pex_rst_irq;
int ep_state;
long link_status;
};
static inline struct tegra_pcie_dw *to_tegra_pcie(struct dw_pcie *pci)
@ -449,9 +450,13 @@ static void pex_ep_event_hot_rst_done(struct tegra_pcie_dw *pcie)
static irqreturn_t tegra_pcie_ep_irq_thread(int irq, void *arg)
{
struct tegra_pcie_dw *pcie = arg;
struct dw_pcie_ep *ep = &pcie->pci.ep;
struct dw_pcie *pci = &pcie->pci;
u32 val, speed;
if (test_and_clear_bit(0, &pcie->link_status))
dw_pcie_ep_linkup(ep);
speed = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA) &
PCI_EXP_LNKSTA_CLS;
clk_set_rate(pcie->core_clk, pcie_gen_freq[speed - 1]);
@ -498,7 +503,6 @@ static irqreturn_t tegra_pcie_ep_irq_thread(int irq, void *arg)
static irqreturn_t tegra_pcie_ep_hard_irq(int irq, void *arg)
{
struct tegra_pcie_dw *pcie = arg;
struct dw_pcie_ep *ep = &pcie->pci.ep;
int spurious = 1;
u32 status_l0, status_l1, link_status;
@ -514,7 +518,8 @@ static irqreturn_t tegra_pcie_ep_hard_irq(int irq, void *arg)
link_status = appl_readl(pcie, APPL_LINK_STATUS);
if (link_status & APPL_LINK_STATUS_RDLH_LINK_UP) {
dev_dbg(pcie->dev, "Link is up with Host\n");
dw_pcie_ep_linkup(ep);
set_bit(0, &pcie->link_status);
return IRQ_WAKE_THREAD;
}
}

View File

@ -826,33 +826,21 @@ static int pci_epf_test_core_init(struct pci_epf *epf)
return 0;
}
static int pci_epf_test_notifier(struct notifier_block *nb, unsigned long val,
void *data)
static int pci_epf_test_link_up(struct pci_epf *epf)
{
struct pci_epf *epf = container_of(nb, struct pci_epf, nb);
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
int ret;
switch (val) {
case CORE_INIT:
ret = pci_epf_test_core_init(epf);
if (ret)
return NOTIFY_BAD;
break;
queue_delayed_work(kpcitest_workqueue, &epf_test->cmd_handler,
msecs_to_jiffies(1));
case LINK_UP:
queue_delayed_work(kpcitest_workqueue, &epf_test->cmd_handler,
msecs_to_jiffies(1));
break;
default:
dev_err(&epf->dev, "Invalid EPF test notifier event\n");
return NOTIFY_BAD;
}
return NOTIFY_OK;
return 0;
}
static const struct pci_epc_event_ops pci_epf_test_event_ops = {
.core_init = pci_epf_test_core_init,
.link_up = pci_epf_test_link_up,
};
static int pci_epf_test_alloc_space(struct pci_epf *epf)
{
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
@ -979,12 +967,8 @@ static int pci_epf_test_bind(struct pci_epf *epf)
if (ret)
epf_test->dma_supported = false;
if (linkup_notifier || core_init_notifier) {
epf->nb.notifier_call = pci_epf_test_notifier;
pci_epc_register_notifier(epc, &epf->nb);
} else {
if (!linkup_notifier && !core_init_notifier)
queue_work(kpcitest_workqueue, &epf_test->cmd_handler.work);
}
return 0;
}
@ -1010,6 +994,8 @@ static int pci_epf_test_probe(struct pci_epf *epf)
INIT_DELAYED_WORK(&epf_test->cmd_handler, pci_epf_test_cmd_handler);
epf->event_ops = &pci_epf_test_event_ops;
epf_set_drvdata(epf, epf_test);
return 0;
}

View File

@ -613,7 +613,7 @@ int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf,
if (type == SECONDARY_INTERFACE && epf->sec_epc)
return -EBUSY;
mutex_lock(&epc->lock);
mutex_lock(&epc->list_lock);
func_no = find_first_zero_bit(&epc->function_num_map,
BITS_PER_LONG);
if (func_no >= BITS_PER_LONG) {
@ -640,7 +640,7 @@ int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf,
list_add_tail(list, &epc->pci_epf);
ret:
mutex_unlock(&epc->lock);
mutex_unlock(&epc->list_lock);
return ret;
}
@ -672,11 +672,11 @@ void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf,
list = &epf->sec_epc_list;
}
mutex_lock(&epc->lock);
mutex_lock(&epc->list_lock);
clear_bit(func_no, &epc->function_num_map);
list_del(list);
epf->epc = NULL;
mutex_unlock(&epc->lock);
mutex_unlock(&epc->list_lock);
}
EXPORT_SYMBOL_GPL(pci_epc_remove_epf);
@ -690,10 +690,19 @@ EXPORT_SYMBOL_GPL(pci_epc_remove_epf);
*/
void pci_epc_linkup(struct pci_epc *epc)
{
struct pci_epf *epf;
if (!epc || IS_ERR(epc))
return;
atomic_notifier_call_chain(&epc->notifier, LINK_UP, NULL);
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->link_up)
epf->event_ops->link_up(epf);
mutex_unlock(&epf->lock);
}
mutex_unlock(&epc->list_lock);
}
EXPORT_SYMBOL_GPL(pci_epc_linkup);
@ -707,10 +716,19 @@ EXPORT_SYMBOL_GPL(pci_epc_linkup);
*/
void pci_epc_init_notify(struct pci_epc *epc)
{
struct pci_epf *epf;
if (!epc || IS_ERR(epc))
return;
atomic_notifier_call_chain(&epc->notifier, CORE_INIT, NULL);
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);
mutex_unlock(&epf->lock);
}
mutex_unlock(&epc->list_lock);
}
EXPORT_SYMBOL_GPL(pci_epc_init_notify);
@ -777,8 +795,8 @@ __pci_epc_create(struct device *dev, const struct pci_epc_ops *ops,
}
mutex_init(&epc->lock);
mutex_init(&epc->list_lock);
INIT_LIST_HEAD(&epc->pci_epf);
ATOMIC_INIT_NOTIFIER_HEAD(&epc->notifier);
device_initialize(&epc->dev);
epc->dev.class = pci_epc_class;

View File

@ -122,6 +122,7 @@ struct pci_epc_mem {
* struct pci_epc - represents the PCI EPC device
* @dev: PCI EPC device
* @pci_epf: list of endpoint functions present in this EPC device
* list_lock: Mutex for protecting pci_epf list
* @ops: function pointers for performing endpoint operations
* @windows: array of address space of the endpoint controller
* @mem: first window of the endpoint controller, which corresponds to
@ -134,11 +135,11 @@ struct pci_epc_mem {
* @group: configfs group representing the PCI EPC device
* @lock: mutex to protect pci_epc ops
* @function_num_map: bitmap to manage physical function number
* @notifier: used to notify EPF of any EPC events (like linkup)
*/
struct pci_epc {
struct device dev;
struct list_head pci_epf;
struct mutex list_lock;
const struct pci_epc_ops *ops;
struct pci_epc_mem **windows;
struct pci_epc_mem *mem;
@ -149,7 +150,6 @@ struct pci_epc {
/* mutex to protect against concurrent access of EP controller */
struct mutex lock;
unsigned long function_num_map;
struct atomic_notifier_head notifier;
};
/**
@ -192,12 +192,6 @@ static inline void *epc_get_drvdata(struct pci_epc *epc)
return dev_get_drvdata(&epc->dev);
}
static inline int
pci_epc_register_notifier(struct pci_epc *epc, struct notifier_block *nb)
{
return atomic_notifier_chain_register(&epc->notifier, nb);
}
struct pci_epc *
__devm_pci_epc_create(struct device *dev, const struct pci_epc_ops *ops,
struct module *owner);

View File

@ -17,11 +17,6 @@
struct pci_epf;
enum pci_epc_interface_type;
enum pci_notify_event {
CORE_INIT,
LINK_UP,
};
enum pci_barno {
NO_BAR = -1,
BAR_0,
@ -72,6 +67,16 @@ struct pci_epf_ops {
struct config_group *group);
};
/**
* struct pci_epf_event_ops - Callbacks for capturing the EPC events
* @core_init: Callback for the EPC initialization complete event
* @link_up: Callback for the EPC link up event
*/
struct pci_epc_event_ops {
int (*core_init)(struct pci_epf *epf);
int (*link_up)(struct pci_epf *epf);
};
/**
* struct pci_epf_driver - represents the PCI EPF driver
* @probe: ops to perform when a new EPF device has been bound to the EPF driver
@ -127,7 +132,6 @@ struct pci_epf_bar {
* @epf_pf: the physical EPF device to which this virtual EPF device is bound
* @driver: the EPF driver to which this EPF device is bound
* @list: to add pci_epf as a list of PCI endpoint functions to pci_epc
* @nb: notifier block to notify EPF of any EPC events (like linkup)
* @lock: mutex to protect pci_epf_ops
* @sec_epc: the secondary EPC device to which this EPF device is bound
* @sec_epc_list: to add pci_epf as list of PCI endpoint functions to secondary
@ -139,6 +143,7 @@ struct pci_epf_bar {
* @is_vf: true - virtual function, false - physical function
* @vfunction_num_map: bitmap to manage virtual function number
* @pci_vepf: list of virtual endpoint functions associated with this function
* @event_ops: Callbacks for capturing the EPC events
*/
struct pci_epf {
struct device dev;
@ -154,7 +159,6 @@ struct pci_epf {
struct pci_epf *epf_pf;
struct pci_epf_driver *driver;
struct list_head list;
struct notifier_block nb;
/* mutex to protect against concurrent access of pci_epf_ops */
struct mutex lock;
@ -168,6 +172,7 @@ struct pci_epf {
unsigned int is_vf;
unsigned long vfunction_num_map;
struct list_head pci_vepf;
const struct pci_epc_event_ops *event_ops;
};
/**