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:
commit
33abd97c34
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user