Commit 33abd97c authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

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
parents 191b4101 f5edd871
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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");
+7 −2
Original line number Diff line number Diff line
@@ -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;
			}
		}

+12 −26
Original line number Diff line number Diff line
@@ -826,32 +826,20 @@ 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;

	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 0;
}

	return NOTIFY_OK;
}
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)
{
@@ -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;
}
+25 −7
Original line number Diff line number Diff line
@@ -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;
+2 −8
Original line number Diff line number Diff line
@@ -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);
Loading