162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/**
362306a36Sopenharmony_ci * Host side endpoint driver to implement Non-Transparent Bridge functionality
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2020 Texas Instruments
662306a36Sopenharmony_ci * Author: Kishon Vijay Abraham I <kishon@ti.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/delay.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/pci.h>
1262306a36Sopenharmony_ci#include <linux/slab.h>
1362306a36Sopenharmony_ci#include <linux/ntb.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define NTB_EPF_COMMAND		0x0
1662306a36Sopenharmony_ci#define CMD_CONFIGURE_DOORBELL	1
1762306a36Sopenharmony_ci#define CMD_TEARDOWN_DOORBELL	2
1862306a36Sopenharmony_ci#define CMD_CONFIGURE_MW	3
1962306a36Sopenharmony_ci#define CMD_TEARDOWN_MW		4
2062306a36Sopenharmony_ci#define CMD_LINK_UP		5
2162306a36Sopenharmony_ci#define CMD_LINK_DOWN		6
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define NTB_EPF_ARGUMENT	0x4
2462306a36Sopenharmony_ci#define MSIX_ENABLE		BIT(16)
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define NTB_EPF_CMD_STATUS	0x8
2762306a36Sopenharmony_ci#define COMMAND_STATUS_OK	1
2862306a36Sopenharmony_ci#define COMMAND_STATUS_ERROR	2
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define NTB_EPF_LINK_STATUS	0x0A
3162306a36Sopenharmony_ci#define LINK_STATUS_UP		BIT(0)
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define NTB_EPF_TOPOLOGY	0x0C
3462306a36Sopenharmony_ci#define NTB_EPF_LOWER_ADDR	0x10
3562306a36Sopenharmony_ci#define NTB_EPF_UPPER_ADDR	0x14
3662306a36Sopenharmony_ci#define NTB_EPF_LOWER_SIZE	0x18
3762306a36Sopenharmony_ci#define NTB_EPF_UPPER_SIZE	0x1C
3862306a36Sopenharmony_ci#define NTB_EPF_MW_COUNT	0x20
3962306a36Sopenharmony_ci#define NTB_EPF_MW1_OFFSET	0x24
4062306a36Sopenharmony_ci#define NTB_EPF_SPAD_OFFSET	0x28
4162306a36Sopenharmony_ci#define NTB_EPF_SPAD_COUNT	0x2C
4262306a36Sopenharmony_ci#define NTB_EPF_DB_ENTRY_SIZE	0x30
4362306a36Sopenharmony_ci#define NTB_EPF_DB_DATA(n)	(0x34 + (n) * 4)
4462306a36Sopenharmony_ci#define NTB_EPF_DB_OFFSET(n)	(0xB4 + (n) * 4)
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define NTB_EPF_MIN_DB_COUNT	3
4762306a36Sopenharmony_ci#define NTB_EPF_MAX_DB_COUNT	31
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define NTB_EPF_COMMAND_TIMEOUT	1000 /* 1 Sec */
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cienum pci_barno {
5262306a36Sopenharmony_ci	BAR_0,
5362306a36Sopenharmony_ci	BAR_1,
5462306a36Sopenharmony_ci	BAR_2,
5562306a36Sopenharmony_ci	BAR_3,
5662306a36Sopenharmony_ci	BAR_4,
5762306a36Sopenharmony_ci	BAR_5,
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistruct ntb_epf_dev {
6162306a36Sopenharmony_ci	struct ntb_dev ntb;
6262306a36Sopenharmony_ci	struct device *dev;
6362306a36Sopenharmony_ci	/* Mutex to protect providing commands to NTB EPF */
6462306a36Sopenharmony_ci	struct mutex cmd_lock;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	enum pci_barno ctrl_reg_bar;
6762306a36Sopenharmony_ci	enum pci_barno peer_spad_reg_bar;
6862306a36Sopenharmony_ci	enum pci_barno db_reg_bar;
6962306a36Sopenharmony_ci	enum pci_barno mw_bar;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	unsigned int mw_count;
7262306a36Sopenharmony_ci	unsigned int spad_count;
7362306a36Sopenharmony_ci	unsigned int db_count;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	void __iomem *ctrl_reg;
7662306a36Sopenharmony_ci	void __iomem *db_reg;
7762306a36Sopenharmony_ci	void __iomem *peer_spad_reg;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	unsigned int self_spad;
8062306a36Sopenharmony_ci	unsigned int peer_spad;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	int db_val;
8362306a36Sopenharmony_ci	u64 db_valid_mask;
8462306a36Sopenharmony_ci};
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci#define ntb_ndev(__ntb) container_of(__ntb, struct ntb_epf_dev, ntb)
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistruct ntb_epf_data {
8962306a36Sopenharmony_ci	/* BAR that contains both control region and self spad region */
9062306a36Sopenharmony_ci	enum pci_barno ctrl_reg_bar;
9162306a36Sopenharmony_ci	/* BAR that contains peer spad region */
9262306a36Sopenharmony_ci	enum pci_barno peer_spad_reg_bar;
9362306a36Sopenharmony_ci	/* BAR that contains Doorbell region and Memory window '1' */
9462306a36Sopenharmony_ci	enum pci_barno db_reg_bar;
9562306a36Sopenharmony_ci	/* BAR that contains memory windows*/
9662306a36Sopenharmony_ci	enum pci_barno mw_bar;
9762306a36Sopenharmony_ci};
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic int ntb_epf_send_command(struct ntb_epf_dev *ndev, u32 command,
10062306a36Sopenharmony_ci				u32 argument)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	ktime_t timeout;
10362306a36Sopenharmony_ci	bool timedout;
10462306a36Sopenharmony_ci	int ret = 0;
10562306a36Sopenharmony_ci	u32 status;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	mutex_lock(&ndev->cmd_lock);
10862306a36Sopenharmony_ci	writel(argument, ndev->ctrl_reg + NTB_EPF_ARGUMENT);
10962306a36Sopenharmony_ci	writel(command, ndev->ctrl_reg + NTB_EPF_COMMAND);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	timeout = ktime_add_ms(ktime_get(), NTB_EPF_COMMAND_TIMEOUT);
11262306a36Sopenharmony_ci	while (1) {
11362306a36Sopenharmony_ci		timedout = ktime_after(ktime_get(), timeout);
11462306a36Sopenharmony_ci		status = readw(ndev->ctrl_reg + NTB_EPF_CMD_STATUS);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci		if (status == COMMAND_STATUS_ERROR) {
11762306a36Sopenharmony_ci			ret = -EINVAL;
11862306a36Sopenharmony_ci			break;
11962306a36Sopenharmony_ci		}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci		if (status == COMMAND_STATUS_OK)
12262306a36Sopenharmony_ci			break;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci		if (WARN_ON(timedout)) {
12562306a36Sopenharmony_ci			ret = -ETIMEDOUT;
12662306a36Sopenharmony_ci			break;
12762306a36Sopenharmony_ci		}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci		usleep_range(5, 10);
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	writew(0, ndev->ctrl_reg + NTB_EPF_CMD_STATUS);
13362306a36Sopenharmony_ci	mutex_unlock(&ndev->cmd_lock);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	return ret;
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic int ntb_epf_mw_to_bar(struct ntb_epf_dev *ndev, int idx)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	struct device *dev = ndev->dev;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	if (idx < 0 || idx > ndev->mw_count) {
14362306a36Sopenharmony_ci		dev_err(dev, "Unsupported Memory Window index %d\n", idx);
14462306a36Sopenharmony_ci		return -EINVAL;
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	return idx + 2;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic int ntb_epf_mw_count(struct ntb_dev *ntb, int pidx)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
15362306a36Sopenharmony_ci	struct device *dev = ndev->dev;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	if (pidx != NTB_DEF_PEER_IDX) {
15662306a36Sopenharmony_ci		dev_err(dev, "Unsupported Peer ID %d\n", pidx);
15762306a36Sopenharmony_ci		return -EINVAL;
15862306a36Sopenharmony_ci	}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	return ndev->mw_count;
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic int ntb_epf_mw_get_align(struct ntb_dev *ntb, int pidx, int idx,
16462306a36Sopenharmony_ci				resource_size_t *addr_align,
16562306a36Sopenharmony_ci				resource_size_t *size_align,
16662306a36Sopenharmony_ci				resource_size_t *size_max)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
16962306a36Sopenharmony_ci	struct device *dev = ndev->dev;
17062306a36Sopenharmony_ci	int bar;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	if (pidx != NTB_DEF_PEER_IDX) {
17362306a36Sopenharmony_ci		dev_err(dev, "Unsupported Peer ID %d\n", pidx);
17462306a36Sopenharmony_ci		return -EINVAL;
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	bar = ntb_epf_mw_to_bar(ndev, idx);
17862306a36Sopenharmony_ci	if (bar < 0)
17962306a36Sopenharmony_ci		return bar;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	if (addr_align)
18262306a36Sopenharmony_ci		*addr_align = SZ_4K;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	if (size_align)
18562306a36Sopenharmony_ci		*size_align = 1;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	if (size_max)
18862306a36Sopenharmony_ci		*size_max = pci_resource_len(ndev->ntb.pdev, bar);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	return 0;
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic u64 ntb_epf_link_is_up(struct ntb_dev *ntb,
19462306a36Sopenharmony_ci			      enum ntb_speed *speed,
19562306a36Sopenharmony_ci			      enum ntb_width *width)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
19862306a36Sopenharmony_ci	u32 status;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	status = readw(ndev->ctrl_reg + NTB_EPF_LINK_STATUS);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	return status & LINK_STATUS_UP;
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic u32 ntb_epf_spad_read(struct ntb_dev *ntb, int idx)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
20862306a36Sopenharmony_ci	struct device *dev = ndev->dev;
20962306a36Sopenharmony_ci	u32 offset;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	if (idx < 0 || idx >= ndev->spad_count) {
21262306a36Sopenharmony_ci		dev_err(dev, "READ: Invalid ScratchPad Index %d\n", idx);
21362306a36Sopenharmony_ci		return 0;
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	offset = readl(ndev->ctrl_reg + NTB_EPF_SPAD_OFFSET);
21762306a36Sopenharmony_ci	offset += (idx << 2);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	return readl(ndev->ctrl_reg + offset);
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cistatic int ntb_epf_spad_write(struct ntb_dev *ntb,
22362306a36Sopenharmony_ci			      int idx, u32 val)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
22662306a36Sopenharmony_ci	struct device *dev = ndev->dev;
22762306a36Sopenharmony_ci	u32 offset;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	if (idx < 0 || idx >= ndev->spad_count) {
23062306a36Sopenharmony_ci		dev_err(dev, "WRITE: Invalid ScratchPad Index %d\n", idx);
23162306a36Sopenharmony_ci		return -EINVAL;
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	offset = readl(ndev->ctrl_reg + NTB_EPF_SPAD_OFFSET);
23562306a36Sopenharmony_ci	offset += (idx << 2);
23662306a36Sopenharmony_ci	writel(val, ndev->ctrl_reg + offset);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	return 0;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic u32 ntb_epf_peer_spad_read(struct ntb_dev *ntb, int pidx, int idx)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
24462306a36Sopenharmony_ci	struct device *dev = ndev->dev;
24562306a36Sopenharmony_ci	u32 offset;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	if (pidx != NTB_DEF_PEER_IDX) {
24862306a36Sopenharmony_ci		dev_err(dev, "Unsupported Peer ID %d\n", pidx);
24962306a36Sopenharmony_ci		return -EINVAL;
25062306a36Sopenharmony_ci	}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	if (idx < 0 || idx >= ndev->spad_count) {
25362306a36Sopenharmony_ci		dev_err(dev, "WRITE: Invalid Peer ScratchPad Index %d\n", idx);
25462306a36Sopenharmony_ci		return -EINVAL;
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	offset = (idx << 2);
25862306a36Sopenharmony_ci	return readl(ndev->peer_spad_reg + offset);
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic int ntb_epf_peer_spad_write(struct ntb_dev *ntb, int pidx,
26262306a36Sopenharmony_ci				   int idx, u32 val)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
26562306a36Sopenharmony_ci	struct device *dev = ndev->dev;
26662306a36Sopenharmony_ci	u32 offset;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	if (pidx != NTB_DEF_PEER_IDX) {
26962306a36Sopenharmony_ci		dev_err(dev, "Unsupported Peer ID %d\n", pidx);
27062306a36Sopenharmony_ci		return -EINVAL;
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	if (idx < 0 || idx >= ndev->spad_count) {
27462306a36Sopenharmony_ci		dev_err(dev, "WRITE: Invalid Peer ScratchPad Index %d\n", idx);
27562306a36Sopenharmony_ci		return -EINVAL;
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	offset = (idx << 2);
27962306a36Sopenharmony_ci	writel(val, ndev->peer_spad_reg + offset);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	return 0;
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_cistatic int ntb_epf_link_enable(struct ntb_dev *ntb,
28562306a36Sopenharmony_ci			       enum ntb_speed max_speed,
28662306a36Sopenharmony_ci			       enum ntb_width max_width)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
28962306a36Sopenharmony_ci	struct device *dev = ndev->dev;
29062306a36Sopenharmony_ci	int ret;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	ret = ntb_epf_send_command(ndev, CMD_LINK_UP, 0);
29362306a36Sopenharmony_ci	if (ret) {
29462306a36Sopenharmony_ci		dev_err(dev, "Fail to enable link\n");
29562306a36Sopenharmony_ci		return ret;
29662306a36Sopenharmony_ci	}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	return 0;
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_cistatic int ntb_epf_link_disable(struct ntb_dev *ntb)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
30462306a36Sopenharmony_ci	struct device *dev = ndev->dev;
30562306a36Sopenharmony_ci	int ret;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	ret = ntb_epf_send_command(ndev, CMD_LINK_DOWN, 0);
30862306a36Sopenharmony_ci	if (ret) {
30962306a36Sopenharmony_ci		dev_err(dev, "Fail to disable link\n");
31062306a36Sopenharmony_ci		return ret;
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	return 0;
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_cistatic irqreturn_t ntb_epf_vec_isr(int irq, void *dev)
31762306a36Sopenharmony_ci{
31862306a36Sopenharmony_ci	struct ntb_epf_dev *ndev = dev;
31962306a36Sopenharmony_ci	int irq_no;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	irq_no = irq - pci_irq_vector(ndev->ntb.pdev, 0);
32262306a36Sopenharmony_ci	ndev->db_val = irq_no + 1;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	if (irq_no == 0)
32562306a36Sopenharmony_ci		ntb_link_event(&ndev->ntb);
32662306a36Sopenharmony_ci	else
32762306a36Sopenharmony_ci		ntb_db_event(&ndev->ntb, irq_no);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	return IRQ_HANDLED;
33062306a36Sopenharmony_ci}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_cistatic int ntb_epf_init_isr(struct ntb_epf_dev *ndev, int msi_min, int msi_max)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	struct pci_dev *pdev = ndev->ntb.pdev;
33562306a36Sopenharmony_ci	struct device *dev = ndev->dev;
33662306a36Sopenharmony_ci	u32 argument = MSIX_ENABLE;
33762306a36Sopenharmony_ci	int irq;
33862306a36Sopenharmony_ci	int ret;
33962306a36Sopenharmony_ci	int i;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	irq = pci_alloc_irq_vectors(pdev, msi_min, msi_max, PCI_IRQ_MSIX);
34262306a36Sopenharmony_ci	if (irq < 0) {
34362306a36Sopenharmony_ci		dev_dbg(dev, "Failed to get MSIX interrupts\n");
34462306a36Sopenharmony_ci		irq = pci_alloc_irq_vectors(pdev, msi_min, msi_max,
34562306a36Sopenharmony_ci					    PCI_IRQ_MSI);
34662306a36Sopenharmony_ci		if (irq < 0) {
34762306a36Sopenharmony_ci			dev_err(dev, "Failed to get MSI interrupts\n");
34862306a36Sopenharmony_ci			return irq;
34962306a36Sopenharmony_ci		}
35062306a36Sopenharmony_ci		argument &= ~MSIX_ENABLE;
35162306a36Sopenharmony_ci	}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	for (i = 0; i < irq; i++) {
35462306a36Sopenharmony_ci		ret = request_irq(pci_irq_vector(pdev, i), ntb_epf_vec_isr,
35562306a36Sopenharmony_ci				  0, "ntb_epf", ndev);
35662306a36Sopenharmony_ci		if (ret) {
35762306a36Sopenharmony_ci			dev_err(dev, "Failed to request irq\n");
35862306a36Sopenharmony_ci			goto err_request_irq;
35962306a36Sopenharmony_ci		}
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	ndev->db_count = irq - 1;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	ret = ntb_epf_send_command(ndev, CMD_CONFIGURE_DOORBELL,
36562306a36Sopenharmony_ci				   argument | irq);
36662306a36Sopenharmony_ci	if (ret) {
36762306a36Sopenharmony_ci		dev_err(dev, "Failed to configure doorbell\n");
36862306a36Sopenharmony_ci		goto err_configure_db;
36962306a36Sopenharmony_ci	}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	return 0;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cierr_configure_db:
37462306a36Sopenharmony_ci	for (i = 0; i < ndev->db_count + 1; i++)
37562306a36Sopenharmony_ci		free_irq(pci_irq_vector(pdev, i), ndev);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_cierr_request_irq:
37862306a36Sopenharmony_ci	pci_free_irq_vectors(pdev);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	return ret;
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cistatic int ntb_epf_peer_mw_count(struct ntb_dev *ntb)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	return ntb_ndev(ntb)->mw_count;
38662306a36Sopenharmony_ci}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_cistatic int ntb_epf_spad_count(struct ntb_dev *ntb)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	return ntb_ndev(ntb)->spad_count;
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_cistatic u64 ntb_epf_db_valid_mask(struct ntb_dev *ntb)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	return ntb_ndev(ntb)->db_valid_mask;
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic int ntb_epf_db_set_mask(struct ntb_dev *ntb, u64 db_bits)
39962306a36Sopenharmony_ci{
40062306a36Sopenharmony_ci	return 0;
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cistatic int ntb_epf_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
40462306a36Sopenharmony_ci				dma_addr_t addr, resource_size_t size)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
40762306a36Sopenharmony_ci	struct device *dev = ndev->dev;
40862306a36Sopenharmony_ci	resource_size_t mw_size;
40962306a36Sopenharmony_ci	int bar;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	if (pidx != NTB_DEF_PEER_IDX) {
41262306a36Sopenharmony_ci		dev_err(dev, "Unsupported Peer ID %d\n", pidx);
41362306a36Sopenharmony_ci		return -EINVAL;
41462306a36Sopenharmony_ci	}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	bar = idx + ndev->mw_bar;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	mw_size = pci_resource_len(ntb->pdev, bar);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	if (size > mw_size) {
42162306a36Sopenharmony_ci		dev_err(dev, "Size:%pa is greater than the MW size %pa\n",
42262306a36Sopenharmony_ci			&size, &mw_size);
42362306a36Sopenharmony_ci		return -EINVAL;
42462306a36Sopenharmony_ci	}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	writel(lower_32_bits(addr), ndev->ctrl_reg + NTB_EPF_LOWER_ADDR);
42762306a36Sopenharmony_ci	writel(upper_32_bits(addr), ndev->ctrl_reg + NTB_EPF_UPPER_ADDR);
42862306a36Sopenharmony_ci	writel(lower_32_bits(size), ndev->ctrl_reg + NTB_EPF_LOWER_SIZE);
42962306a36Sopenharmony_ci	writel(upper_32_bits(size), ndev->ctrl_reg + NTB_EPF_UPPER_SIZE);
43062306a36Sopenharmony_ci	ntb_epf_send_command(ndev, CMD_CONFIGURE_MW, idx);
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	return 0;
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_cistatic int ntb_epf_mw_clear_trans(struct ntb_dev *ntb, int pidx, int idx)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
43862306a36Sopenharmony_ci	struct device *dev = ndev->dev;
43962306a36Sopenharmony_ci	int ret = 0;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	ntb_epf_send_command(ndev, CMD_TEARDOWN_MW, idx);
44262306a36Sopenharmony_ci	if (ret)
44362306a36Sopenharmony_ci		dev_err(dev, "Failed to teardown memory window\n");
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	return ret;
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_cistatic int ntb_epf_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
44962306a36Sopenharmony_ci				    phys_addr_t *base, resource_size_t *size)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
45262306a36Sopenharmony_ci	u32 offset = 0;
45362306a36Sopenharmony_ci	int bar;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	if (idx == 0)
45662306a36Sopenharmony_ci		offset = readl(ndev->ctrl_reg + NTB_EPF_MW1_OFFSET);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	bar = idx + ndev->mw_bar;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	if (base)
46162306a36Sopenharmony_ci		*base = pci_resource_start(ndev->ntb.pdev, bar) + offset;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	if (size)
46462306a36Sopenharmony_ci		*size = pci_resource_len(ndev->ntb.pdev, bar) - offset;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	return 0;
46762306a36Sopenharmony_ci}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_cistatic int ntb_epf_peer_db_set(struct ntb_dev *ntb, u64 db_bits)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
47262306a36Sopenharmony_ci	u32 interrupt_num = ffs(db_bits) + 1;
47362306a36Sopenharmony_ci	struct device *dev = ndev->dev;
47462306a36Sopenharmony_ci	u32 db_entry_size;
47562306a36Sopenharmony_ci	u32 db_offset;
47662306a36Sopenharmony_ci	u32 db_data;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	if (interrupt_num > ndev->db_count) {
47962306a36Sopenharmony_ci		dev_err(dev, "DB interrupt %d greater than Max Supported %d\n",
48062306a36Sopenharmony_ci			interrupt_num, ndev->db_count);
48162306a36Sopenharmony_ci		return -EINVAL;
48262306a36Sopenharmony_ci	}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	db_entry_size = readl(ndev->ctrl_reg + NTB_EPF_DB_ENTRY_SIZE);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	db_data = readl(ndev->ctrl_reg + NTB_EPF_DB_DATA(interrupt_num));
48762306a36Sopenharmony_ci	db_offset = readl(ndev->ctrl_reg + NTB_EPF_DB_OFFSET(interrupt_num));
48862306a36Sopenharmony_ci	writel(db_data, ndev->db_reg + (db_entry_size * interrupt_num) +
48962306a36Sopenharmony_ci	       db_offset);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	return 0;
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_cistatic u64 ntb_epf_db_read(struct ntb_dev *ntb)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	return ndev->db_val;
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cistatic int ntb_epf_db_clear_mask(struct ntb_dev *ntb, u64 db_bits)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	return 0;
50462306a36Sopenharmony_ci}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_cistatic int ntb_epf_db_clear(struct ntb_dev *ntb, u64 db_bits)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	struct ntb_epf_dev *ndev = ntb_ndev(ntb);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	ndev->db_val = 0;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	return 0;
51362306a36Sopenharmony_ci}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_cistatic const struct ntb_dev_ops ntb_epf_ops = {
51662306a36Sopenharmony_ci	.mw_count		= ntb_epf_mw_count,
51762306a36Sopenharmony_ci	.spad_count		= ntb_epf_spad_count,
51862306a36Sopenharmony_ci	.peer_mw_count		= ntb_epf_peer_mw_count,
51962306a36Sopenharmony_ci	.db_valid_mask		= ntb_epf_db_valid_mask,
52062306a36Sopenharmony_ci	.db_set_mask		= ntb_epf_db_set_mask,
52162306a36Sopenharmony_ci	.mw_set_trans		= ntb_epf_mw_set_trans,
52262306a36Sopenharmony_ci	.mw_clear_trans		= ntb_epf_mw_clear_trans,
52362306a36Sopenharmony_ci	.peer_mw_get_addr	= ntb_epf_peer_mw_get_addr,
52462306a36Sopenharmony_ci	.link_enable		= ntb_epf_link_enable,
52562306a36Sopenharmony_ci	.spad_read		= ntb_epf_spad_read,
52662306a36Sopenharmony_ci	.spad_write		= ntb_epf_spad_write,
52762306a36Sopenharmony_ci	.peer_spad_read		= ntb_epf_peer_spad_read,
52862306a36Sopenharmony_ci	.peer_spad_write	= ntb_epf_peer_spad_write,
52962306a36Sopenharmony_ci	.peer_db_set		= ntb_epf_peer_db_set,
53062306a36Sopenharmony_ci	.db_read		= ntb_epf_db_read,
53162306a36Sopenharmony_ci	.mw_get_align		= ntb_epf_mw_get_align,
53262306a36Sopenharmony_ci	.link_is_up		= ntb_epf_link_is_up,
53362306a36Sopenharmony_ci	.db_clear_mask		= ntb_epf_db_clear_mask,
53462306a36Sopenharmony_ci	.db_clear		= ntb_epf_db_clear,
53562306a36Sopenharmony_ci	.link_disable		= ntb_epf_link_disable,
53662306a36Sopenharmony_ci};
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_cistatic inline void ntb_epf_init_struct(struct ntb_epf_dev *ndev,
53962306a36Sopenharmony_ci				       struct pci_dev *pdev)
54062306a36Sopenharmony_ci{
54162306a36Sopenharmony_ci	ndev->ntb.pdev = pdev;
54262306a36Sopenharmony_ci	ndev->ntb.topo = NTB_TOPO_NONE;
54362306a36Sopenharmony_ci	ndev->ntb.ops = &ntb_epf_ops;
54462306a36Sopenharmony_ci}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_cistatic int ntb_epf_init_dev(struct ntb_epf_dev *ndev)
54762306a36Sopenharmony_ci{
54862306a36Sopenharmony_ci	struct device *dev = ndev->dev;
54962306a36Sopenharmony_ci	int ret;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	/* One Link interrupt and rest doorbell interrupt */
55262306a36Sopenharmony_ci	ret = ntb_epf_init_isr(ndev, NTB_EPF_MIN_DB_COUNT + 1,
55362306a36Sopenharmony_ci			       NTB_EPF_MAX_DB_COUNT + 1);
55462306a36Sopenharmony_ci	if (ret) {
55562306a36Sopenharmony_ci		dev_err(dev, "Failed to init ISR\n");
55662306a36Sopenharmony_ci		return ret;
55762306a36Sopenharmony_ci	}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1;
56062306a36Sopenharmony_ci	ndev->mw_count = readl(ndev->ctrl_reg + NTB_EPF_MW_COUNT);
56162306a36Sopenharmony_ci	ndev->spad_count = readl(ndev->ctrl_reg + NTB_EPF_SPAD_COUNT);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	return 0;
56462306a36Sopenharmony_ci}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_cistatic int ntb_epf_init_pci(struct ntb_epf_dev *ndev,
56762306a36Sopenharmony_ci			    struct pci_dev *pdev)
56862306a36Sopenharmony_ci{
56962306a36Sopenharmony_ci	struct device *dev = ndev->dev;
57062306a36Sopenharmony_ci	size_t spad_sz, spad_off;
57162306a36Sopenharmony_ci	int ret;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	pci_set_drvdata(pdev, ndev);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	ret = pci_enable_device(pdev);
57662306a36Sopenharmony_ci	if (ret) {
57762306a36Sopenharmony_ci		dev_err(dev, "Cannot enable PCI device\n");
57862306a36Sopenharmony_ci		goto err_pci_enable;
57962306a36Sopenharmony_ci	}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	ret = pci_request_regions(pdev, "ntb");
58262306a36Sopenharmony_ci	if (ret) {
58362306a36Sopenharmony_ci		dev_err(dev, "Cannot obtain PCI resources\n");
58462306a36Sopenharmony_ci		goto err_pci_regions;
58562306a36Sopenharmony_ci	}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	pci_set_master(pdev);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
59062306a36Sopenharmony_ci	if (ret) {
59162306a36Sopenharmony_ci		ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
59262306a36Sopenharmony_ci		if (ret) {
59362306a36Sopenharmony_ci			dev_err(dev, "Cannot set DMA mask\n");
59462306a36Sopenharmony_ci			goto err_pci_regions;
59562306a36Sopenharmony_ci		}
59662306a36Sopenharmony_ci		dev_warn(&pdev->dev, "Cannot DMA highmem\n");
59762306a36Sopenharmony_ci	}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	ndev->ctrl_reg = pci_iomap(pdev, ndev->ctrl_reg_bar, 0);
60062306a36Sopenharmony_ci	if (!ndev->ctrl_reg) {
60162306a36Sopenharmony_ci		ret = -EIO;
60262306a36Sopenharmony_ci		goto err_pci_regions;
60362306a36Sopenharmony_ci	}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	if (ndev->peer_spad_reg_bar) {
60662306a36Sopenharmony_ci		ndev->peer_spad_reg = pci_iomap(pdev, ndev->peer_spad_reg_bar, 0);
60762306a36Sopenharmony_ci		if (!ndev->peer_spad_reg) {
60862306a36Sopenharmony_ci			ret = -EIO;
60962306a36Sopenharmony_ci			goto err_pci_regions;
61062306a36Sopenharmony_ci		}
61162306a36Sopenharmony_ci	} else {
61262306a36Sopenharmony_ci		spad_sz = 4 * readl(ndev->ctrl_reg + NTB_EPF_SPAD_COUNT);
61362306a36Sopenharmony_ci		spad_off = readl(ndev->ctrl_reg + NTB_EPF_SPAD_OFFSET);
61462306a36Sopenharmony_ci		ndev->peer_spad_reg = ndev->ctrl_reg + spad_off  + spad_sz;
61562306a36Sopenharmony_ci	}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	ndev->db_reg = pci_iomap(pdev, ndev->db_reg_bar, 0);
61862306a36Sopenharmony_ci	if (!ndev->db_reg) {
61962306a36Sopenharmony_ci		ret = -EIO;
62062306a36Sopenharmony_ci		goto err_pci_regions;
62162306a36Sopenharmony_ci	}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	return 0;
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_cierr_pci_regions:
62662306a36Sopenharmony_ci	pci_disable_device(pdev);
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_cierr_pci_enable:
62962306a36Sopenharmony_ci	pci_set_drvdata(pdev, NULL);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	return ret;
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_cistatic void ntb_epf_deinit_pci(struct ntb_epf_dev *ndev)
63562306a36Sopenharmony_ci{
63662306a36Sopenharmony_ci	struct pci_dev *pdev = ndev->ntb.pdev;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	pci_iounmap(pdev, ndev->ctrl_reg);
63962306a36Sopenharmony_ci	pci_iounmap(pdev, ndev->peer_spad_reg);
64062306a36Sopenharmony_ci	pci_iounmap(pdev, ndev->db_reg);
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	pci_release_regions(pdev);
64362306a36Sopenharmony_ci	pci_disable_device(pdev);
64462306a36Sopenharmony_ci	pci_set_drvdata(pdev, NULL);
64562306a36Sopenharmony_ci}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_cistatic void ntb_epf_cleanup_isr(struct ntb_epf_dev *ndev)
64862306a36Sopenharmony_ci{
64962306a36Sopenharmony_ci	struct pci_dev *pdev = ndev->ntb.pdev;
65062306a36Sopenharmony_ci	int i;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	ntb_epf_send_command(ndev, CMD_TEARDOWN_DOORBELL, ndev->db_count + 1);
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	for (i = 0; i < ndev->db_count + 1; i++)
65562306a36Sopenharmony_ci		free_irq(pci_irq_vector(pdev, i), ndev);
65662306a36Sopenharmony_ci	pci_free_irq_vectors(pdev);
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_cistatic int ntb_epf_pci_probe(struct pci_dev *pdev,
66062306a36Sopenharmony_ci			     const struct pci_device_id *id)
66162306a36Sopenharmony_ci{
66262306a36Sopenharmony_ci	enum pci_barno peer_spad_reg_bar = BAR_1;
66362306a36Sopenharmony_ci	enum pci_barno ctrl_reg_bar = BAR_0;
66462306a36Sopenharmony_ci	enum pci_barno db_reg_bar = BAR_2;
66562306a36Sopenharmony_ci	enum pci_barno mw_bar = BAR_2;
66662306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
66762306a36Sopenharmony_ci	struct ntb_epf_data *data;
66862306a36Sopenharmony_ci	struct ntb_epf_dev *ndev;
66962306a36Sopenharmony_ci	int ret;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	if (pci_is_bridge(pdev))
67262306a36Sopenharmony_ci		return -ENODEV;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	ndev = devm_kzalloc(dev, sizeof(*ndev), GFP_KERNEL);
67562306a36Sopenharmony_ci	if (!ndev)
67662306a36Sopenharmony_ci		return -ENOMEM;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	data = (struct ntb_epf_data *)id->driver_data;
67962306a36Sopenharmony_ci	if (data) {
68062306a36Sopenharmony_ci		peer_spad_reg_bar = data->peer_spad_reg_bar;
68162306a36Sopenharmony_ci		ctrl_reg_bar = data->ctrl_reg_bar;
68262306a36Sopenharmony_ci		db_reg_bar = data->db_reg_bar;
68362306a36Sopenharmony_ci		mw_bar = data->mw_bar;
68462306a36Sopenharmony_ci	}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	ndev->peer_spad_reg_bar = peer_spad_reg_bar;
68762306a36Sopenharmony_ci	ndev->ctrl_reg_bar = ctrl_reg_bar;
68862306a36Sopenharmony_ci	ndev->db_reg_bar = db_reg_bar;
68962306a36Sopenharmony_ci	ndev->mw_bar = mw_bar;
69062306a36Sopenharmony_ci	ndev->dev = dev;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	ntb_epf_init_struct(ndev, pdev);
69362306a36Sopenharmony_ci	mutex_init(&ndev->cmd_lock);
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	ret = ntb_epf_init_pci(ndev, pdev);
69662306a36Sopenharmony_ci	if (ret) {
69762306a36Sopenharmony_ci		dev_err(dev, "Failed to init PCI\n");
69862306a36Sopenharmony_ci		return ret;
69962306a36Sopenharmony_ci	}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	ret = ntb_epf_init_dev(ndev);
70262306a36Sopenharmony_ci	if (ret) {
70362306a36Sopenharmony_ci		dev_err(dev, "Failed to init device\n");
70462306a36Sopenharmony_ci		goto err_init_dev;
70562306a36Sopenharmony_ci	}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	ret = ntb_register_device(&ndev->ntb);
70862306a36Sopenharmony_ci	if (ret) {
70962306a36Sopenharmony_ci		dev_err(dev, "Failed to register NTB device\n");
71062306a36Sopenharmony_ci		goto err_register_dev;
71162306a36Sopenharmony_ci	}
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	return 0;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_cierr_register_dev:
71662306a36Sopenharmony_ci	ntb_epf_cleanup_isr(ndev);
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_cierr_init_dev:
71962306a36Sopenharmony_ci	ntb_epf_deinit_pci(ndev);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	return ret;
72262306a36Sopenharmony_ci}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_cistatic void ntb_epf_pci_remove(struct pci_dev *pdev)
72562306a36Sopenharmony_ci{
72662306a36Sopenharmony_ci	struct ntb_epf_dev *ndev = pci_get_drvdata(pdev);
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	ntb_unregister_device(&ndev->ntb);
72962306a36Sopenharmony_ci	ntb_epf_cleanup_isr(ndev);
73062306a36Sopenharmony_ci	ntb_epf_deinit_pci(ndev);
73162306a36Sopenharmony_ci}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_cistatic const struct ntb_epf_data j721e_data = {
73462306a36Sopenharmony_ci	.ctrl_reg_bar = BAR_0,
73562306a36Sopenharmony_ci	.peer_spad_reg_bar = BAR_1,
73662306a36Sopenharmony_ci	.db_reg_bar = BAR_2,
73762306a36Sopenharmony_ci	.mw_bar = BAR_2,
73862306a36Sopenharmony_ci};
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_cistatic const struct ntb_epf_data mx8_data = {
74162306a36Sopenharmony_ci	.ctrl_reg_bar = BAR_0,
74262306a36Sopenharmony_ci	.peer_spad_reg_bar = BAR_0,
74362306a36Sopenharmony_ci	.db_reg_bar = BAR_2,
74462306a36Sopenharmony_ci	.mw_bar = BAR_4,
74562306a36Sopenharmony_ci};
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_cistatic const struct pci_device_id ntb_epf_pci_tbl[] = {
74862306a36Sopenharmony_ci	{
74962306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E),
75062306a36Sopenharmony_ci		.class = PCI_CLASS_MEMORY_RAM << 8, .class_mask = 0xffff00,
75162306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&j721e_data,
75262306a36Sopenharmony_ci	},
75362306a36Sopenharmony_ci	{
75462306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x0809),
75562306a36Sopenharmony_ci		.class = PCI_CLASS_MEMORY_RAM << 8, .class_mask = 0xffff00,
75662306a36Sopenharmony_ci		.driver_data = (kernel_ulong_t)&mx8_data,
75762306a36Sopenharmony_ci	},
75862306a36Sopenharmony_ci	{ },
75962306a36Sopenharmony_ci};
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_cistatic struct pci_driver ntb_epf_pci_driver = {
76262306a36Sopenharmony_ci	.name		= KBUILD_MODNAME,
76362306a36Sopenharmony_ci	.id_table	= ntb_epf_pci_tbl,
76462306a36Sopenharmony_ci	.probe		= ntb_epf_pci_probe,
76562306a36Sopenharmony_ci	.remove		= ntb_epf_pci_remove,
76662306a36Sopenharmony_ci};
76762306a36Sopenharmony_cimodule_pci_driver(ntb_epf_pci_driver);
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ciMODULE_DESCRIPTION("PCI ENDPOINT NTB HOST DRIVER");
77062306a36Sopenharmony_ciMODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
77162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
772