18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/**
38c2ecf20Sopenharmony_ci * Test driver to test endpoint functionality
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2017 Texas Instruments
68c2ecf20Sopenharmony_ci * Author: Kishon Vijay Abraham I <kishon@ti.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/crc32.h>
108c2ecf20Sopenharmony_ci#include <linux/delay.h>
118c2ecf20Sopenharmony_ci#include <linux/dmaengine.h>
128c2ecf20Sopenharmony_ci#include <linux/io.h>
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <linux/pci_ids.h>
168c2ecf20Sopenharmony_ci#include <linux/random.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/pci-epc.h>
198c2ecf20Sopenharmony_ci#include <linux/pci-epf.h>
208c2ecf20Sopenharmony_ci#include <linux/pci_regs.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define IRQ_TYPE_LEGACY			0
238c2ecf20Sopenharmony_ci#define IRQ_TYPE_MSI			1
248c2ecf20Sopenharmony_ci#define IRQ_TYPE_MSIX			2
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define COMMAND_RAISE_LEGACY_IRQ	BIT(0)
278c2ecf20Sopenharmony_ci#define COMMAND_RAISE_MSI_IRQ		BIT(1)
288c2ecf20Sopenharmony_ci#define COMMAND_RAISE_MSIX_IRQ		BIT(2)
298c2ecf20Sopenharmony_ci#define COMMAND_READ			BIT(3)
308c2ecf20Sopenharmony_ci#define COMMAND_WRITE			BIT(4)
318c2ecf20Sopenharmony_ci#define COMMAND_COPY			BIT(5)
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define STATUS_READ_SUCCESS		BIT(0)
348c2ecf20Sopenharmony_ci#define STATUS_READ_FAIL		BIT(1)
358c2ecf20Sopenharmony_ci#define STATUS_WRITE_SUCCESS		BIT(2)
368c2ecf20Sopenharmony_ci#define STATUS_WRITE_FAIL		BIT(3)
378c2ecf20Sopenharmony_ci#define STATUS_COPY_SUCCESS		BIT(4)
388c2ecf20Sopenharmony_ci#define STATUS_COPY_FAIL		BIT(5)
398c2ecf20Sopenharmony_ci#define STATUS_IRQ_RAISED		BIT(6)
408c2ecf20Sopenharmony_ci#define STATUS_SRC_ADDR_INVALID		BIT(7)
418c2ecf20Sopenharmony_ci#define STATUS_DST_ADDR_INVALID		BIT(8)
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define FLAG_USE_DMA			BIT(0)
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#define TIMER_RESOLUTION		1
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic struct workqueue_struct *kpcitest_workqueue;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistruct pci_epf_test {
508c2ecf20Sopenharmony_ci	void			*reg[PCI_STD_NUM_BARS];
518c2ecf20Sopenharmony_ci	struct pci_epf		*epf;
528c2ecf20Sopenharmony_ci	enum pci_barno		test_reg_bar;
538c2ecf20Sopenharmony_ci	size_t			msix_table_offset;
548c2ecf20Sopenharmony_ci	struct delayed_work	cmd_handler;
558c2ecf20Sopenharmony_ci	struct dma_chan		*dma_chan;
568c2ecf20Sopenharmony_ci	struct completion	transfer_complete;
578c2ecf20Sopenharmony_ci	bool			dma_supported;
588c2ecf20Sopenharmony_ci	const struct pci_epc_features *epc_features;
598c2ecf20Sopenharmony_ci};
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistruct pci_epf_test_reg {
628c2ecf20Sopenharmony_ci	u32	magic;
638c2ecf20Sopenharmony_ci	u32	command;
648c2ecf20Sopenharmony_ci	u32	status;
658c2ecf20Sopenharmony_ci	u64	src_addr;
668c2ecf20Sopenharmony_ci	u64	dst_addr;
678c2ecf20Sopenharmony_ci	u32	size;
688c2ecf20Sopenharmony_ci	u32	checksum;
698c2ecf20Sopenharmony_ci	u32	irq_type;
708c2ecf20Sopenharmony_ci	u32	irq_number;
718c2ecf20Sopenharmony_ci	u32	flags;
728c2ecf20Sopenharmony_ci} __packed;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic struct pci_epf_header test_header = {
758c2ecf20Sopenharmony_ci	.vendorid	= PCI_ANY_ID,
768c2ecf20Sopenharmony_ci	.deviceid	= PCI_ANY_ID,
778c2ecf20Sopenharmony_ci	.baseclass_code = PCI_CLASS_OTHERS,
788c2ecf20Sopenharmony_ci	.interrupt_pin	= PCI_INTERRUPT_INTA,
798c2ecf20Sopenharmony_ci};
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic size_t bar_size[] = { 512, 512, 1024, 16384, 131072, 1048576 };
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic void pci_epf_test_dma_callback(void *param)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	struct pci_epf_test *epf_test = param;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	complete(&epf_test->transfer_complete);
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci/**
918c2ecf20Sopenharmony_ci * pci_epf_test_data_transfer() - Function that uses dmaengine API to transfer
928c2ecf20Sopenharmony_ci *				  data between PCIe EP and remote PCIe RC
938c2ecf20Sopenharmony_ci * @epf_test: the EPF test device that performs the data transfer operation
948c2ecf20Sopenharmony_ci * @dma_dst: The destination address of the data transfer. It can be a physical
958c2ecf20Sopenharmony_ci *	     address given by pci_epc_mem_alloc_addr or DMA mapping APIs.
968c2ecf20Sopenharmony_ci * @dma_src: The source address of the data transfer. It can be a physical
978c2ecf20Sopenharmony_ci *	     address given by pci_epc_mem_alloc_addr or DMA mapping APIs.
988c2ecf20Sopenharmony_ci * @len: The size of the data transfer
998c2ecf20Sopenharmony_ci *
1008c2ecf20Sopenharmony_ci * Function that uses dmaengine API to transfer data between PCIe EP and remote
1018c2ecf20Sopenharmony_ci * PCIe RC. The source and destination address can be a physical address given
1028c2ecf20Sopenharmony_ci * by pci_epc_mem_alloc_addr or the one obtained using DMA mapping APIs.
1038c2ecf20Sopenharmony_ci *
1048c2ecf20Sopenharmony_ci * The function returns '0' on success and negative value on failure.
1058c2ecf20Sopenharmony_ci */
1068c2ecf20Sopenharmony_cistatic int pci_epf_test_data_transfer(struct pci_epf_test *epf_test,
1078c2ecf20Sopenharmony_ci				      dma_addr_t dma_dst, dma_addr_t dma_src,
1088c2ecf20Sopenharmony_ci				      size_t len)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
1118c2ecf20Sopenharmony_ci	struct dma_chan *chan = epf_test->dma_chan;
1128c2ecf20Sopenharmony_ci	struct pci_epf *epf = epf_test->epf;
1138c2ecf20Sopenharmony_ci	struct dma_async_tx_descriptor *tx;
1148c2ecf20Sopenharmony_ci	struct device *dev = &epf->dev;
1158c2ecf20Sopenharmony_ci	dma_cookie_t cookie;
1168c2ecf20Sopenharmony_ci	int ret;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	if (IS_ERR_OR_NULL(chan)) {
1198c2ecf20Sopenharmony_ci		dev_err(dev, "Invalid DMA memcpy channel\n");
1208c2ecf20Sopenharmony_ci		return -EINVAL;
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	tx = dmaengine_prep_dma_memcpy(chan, dma_dst, dma_src, len, flags);
1248c2ecf20Sopenharmony_ci	if (!tx) {
1258c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to prepare DMA memcpy\n");
1268c2ecf20Sopenharmony_ci		return -EIO;
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	tx->callback = pci_epf_test_dma_callback;
1308c2ecf20Sopenharmony_ci	tx->callback_param = epf_test;
1318c2ecf20Sopenharmony_ci	cookie = tx->tx_submit(tx);
1328c2ecf20Sopenharmony_ci	reinit_completion(&epf_test->transfer_complete);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	ret = dma_submit_error(cookie);
1358c2ecf20Sopenharmony_ci	if (ret) {
1368c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to do DMA tx_submit %d\n", cookie);
1378c2ecf20Sopenharmony_ci		return -EIO;
1388c2ecf20Sopenharmony_ci	}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	dma_async_issue_pending(chan);
1418c2ecf20Sopenharmony_ci	ret = wait_for_completion_interruptible(&epf_test->transfer_complete);
1428c2ecf20Sopenharmony_ci	if (ret < 0) {
1438c2ecf20Sopenharmony_ci		dmaengine_terminate_sync(chan);
1448c2ecf20Sopenharmony_ci		dev_err(dev, "DMA wait_for_completion_timeout\n");
1458c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	return 0;
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci/**
1528c2ecf20Sopenharmony_ci * pci_epf_test_init_dma_chan() - Function to initialize EPF test DMA channel
1538c2ecf20Sopenharmony_ci * @epf_test: the EPF test device that performs data transfer operation
1548c2ecf20Sopenharmony_ci *
1558c2ecf20Sopenharmony_ci * Function to initialize EPF test DMA channel.
1568c2ecf20Sopenharmony_ci */
1578c2ecf20Sopenharmony_cistatic int pci_epf_test_init_dma_chan(struct pci_epf_test *epf_test)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	struct pci_epf *epf = epf_test->epf;
1608c2ecf20Sopenharmony_ci	struct device *dev = &epf->dev;
1618c2ecf20Sopenharmony_ci	struct dma_chan *dma_chan;
1628c2ecf20Sopenharmony_ci	dma_cap_mask_t mask;
1638c2ecf20Sopenharmony_ci	int ret;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	dma_cap_zero(mask);
1668c2ecf20Sopenharmony_ci	dma_cap_set(DMA_MEMCPY, mask);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	dma_chan = dma_request_chan_by_mask(&mask);
1698c2ecf20Sopenharmony_ci	if (IS_ERR(dma_chan)) {
1708c2ecf20Sopenharmony_ci		ret = PTR_ERR(dma_chan);
1718c2ecf20Sopenharmony_ci		if (ret != -EPROBE_DEFER)
1728c2ecf20Sopenharmony_ci			dev_err(dev, "Failed to get DMA channel\n");
1738c2ecf20Sopenharmony_ci		return ret;
1748c2ecf20Sopenharmony_ci	}
1758c2ecf20Sopenharmony_ci	init_completion(&epf_test->transfer_complete);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	epf_test->dma_chan = dma_chan;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	return 0;
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci/**
1838c2ecf20Sopenharmony_ci * pci_epf_test_clean_dma_chan() - Function to cleanup EPF test DMA channel
1848c2ecf20Sopenharmony_ci * @epf_test: the EPF test device that performs data transfer operation
1858c2ecf20Sopenharmony_ci *
1868c2ecf20Sopenharmony_ci * Helper to cleanup EPF test DMA channel.
1878c2ecf20Sopenharmony_ci */
1888c2ecf20Sopenharmony_cistatic void pci_epf_test_clean_dma_chan(struct pci_epf_test *epf_test)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	if (!epf_test->dma_supported)
1918c2ecf20Sopenharmony_ci		return;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	dma_release_channel(epf_test->dma_chan);
1948c2ecf20Sopenharmony_ci	epf_test->dma_chan = NULL;
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic void pci_epf_test_print_rate(const char *ops, u64 size,
1988c2ecf20Sopenharmony_ci				    struct timespec64 *start,
1998c2ecf20Sopenharmony_ci				    struct timespec64 *end, bool dma)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	struct timespec64 ts;
2028c2ecf20Sopenharmony_ci	u64 rate, ns;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	ts = timespec64_sub(*end, *start);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	/* convert both size (stored in 'rate') and time in terms of 'ns' */
2078c2ecf20Sopenharmony_ci	ns = timespec64_to_ns(&ts);
2088c2ecf20Sopenharmony_ci	rate = size * NSEC_PER_SEC;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	/* Divide both size (stored in 'rate') and ns by a common factor */
2118c2ecf20Sopenharmony_ci	while (ns > UINT_MAX) {
2128c2ecf20Sopenharmony_ci		rate >>= 1;
2138c2ecf20Sopenharmony_ci		ns >>= 1;
2148c2ecf20Sopenharmony_ci	}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	if (!ns)
2178c2ecf20Sopenharmony_ci		return;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	/* calculate the rate */
2208c2ecf20Sopenharmony_ci	do_div(rate, (uint32_t)ns);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	pr_info("\n%s => Size: %llu bytes\t DMA: %s\t Time: %llu.%09u seconds\t"
2238c2ecf20Sopenharmony_ci		"Rate: %llu KB/s\n", ops, size, dma ? "YES" : "NO",
2248c2ecf20Sopenharmony_ci		(u64)ts.tv_sec, (u32)ts.tv_nsec, rate / 1024);
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic int pci_epf_test_copy(struct pci_epf_test *epf_test)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	int ret;
2308c2ecf20Sopenharmony_ci	bool use_dma;
2318c2ecf20Sopenharmony_ci	void __iomem *src_addr;
2328c2ecf20Sopenharmony_ci	void __iomem *dst_addr;
2338c2ecf20Sopenharmony_ci	phys_addr_t src_phys_addr;
2348c2ecf20Sopenharmony_ci	phys_addr_t dst_phys_addr;
2358c2ecf20Sopenharmony_ci	struct timespec64 start, end;
2368c2ecf20Sopenharmony_ci	struct pci_epf *epf = epf_test->epf;
2378c2ecf20Sopenharmony_ci	struct device *dev = &epf->dev;
2388c2ecf20Sopenharmony_ci	struct pci_epc *epc = epf->epc;
2398c2ecf20Sopenharmony_ci	enum pci_barno test_reg_bar = epf_test->test_reg_bar;
2408c2ecf20Sopenharmony_ci	struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	src_addr = pci_epc_mem_alloc_addr(epc, &src_phys_addr, reg->size);
2438c2ecf20Sopenharmony_ci	if (!src_addr) {
2448c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to allocate source address\n");
2458c2ecf20Sopenharmony_ci		reg->status = STATUS_SRC_ADDR_INVALID;
2468c2ecf20Sopenharmony_ci		ret = -ENOMEM;
2478c2ecf20Sopenharmony_ci		goto err;
2488c2ecf20Sopenharmony_ci	}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	ret = pci_epc_map_addr(epc, epf->func_no, src_phys_addr, reg->src_addr,
2518c2ecf20Sopenharmony_ci			       reg->size);
2528c2ecf20Sopenharmony_ci	if (ret) {
2538c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to map source address\n");
2548c2ecf20Sopenharmony_ci		reg->status = STATUS_SRC_ADDR_INVALID;
2558c2ecf20Sopenharmony_ci		goto err_src_addr;
2568c2ecf20Sopenharmony_ci	}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	dst_addr = pci_epc_mem_alloc_addr(epc, &dst_phys_addr, reg->size);
2598c2ecf20Sopenharmony_ci	if (!dst_addr) {
2608c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to allocate destination address\n");
2618c2ecf20Sopenharmony_ci		reg->status = STATUS_DST_ADDR_INVALID;
2628c2ecf20Sopenharmony_ci		ret = -ENOMEM;
2638c2ecf20Sopenharmony_ci		goto err_src_map_addr;
2648c2ecf20Sopenharmony_ci	}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	ret = pci_epc_map_addr(epc, epf->func_no, dst_phys_addr, reg->dst_addr,
2678c2ecf20Sopenharmony_ci			       reg->size);
2688c2ecf20Sopenharmony_ci	if (ret) {
2698c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to map destination address\n");
2708c2ecf20Sopenharmony_ci		reg->status = STATUS_DST_ADDR_INVALID;
2718c2ecf20Sopenharmony_ci		goto err_dst_addr;
2728c2ecf20Sopenharmony_ci	}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	ktime_get_ts64(&start);
2758c2ecf20Sopenharmony_ci	use_dma = !!(reg->flags & FLAG_USE_DMA);
2768c2ecf20Sopenharmony_ci	if (use_dma) {
2778c2ecf20Sopenharmony_ci		if (!epf_test->dma_supported) {
2788c2ecf20Sopenharmony_ci			dev_err(dev, "Cannot transfer data using DMA\n");
2798c2ecf20Sopenharmony_ci			ret = -EINVAL;
2808c2ecf20Sopenharmony_ci			goto err_map_addr;
2818c2ecf20Sopenharmony_ci		}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci		ret = pci_epf_test_data_transfer(epf_test, dst_phys_addr,
2848c2ecf20Sopenharmony_ci						 src_phys_addr, reg->size);
2858c2ecf20Sopenharmony_ci		if (ret)
2868c2ecf20Sopenharmony_ci			dev_err(dev, "Data transfer failed\n");
2878c2ecf20Sopenharmony_ci	} else {
2888c2ecf20Sopenharmony_ci		void *buf;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci		buf = kzalloc(reg->size, GFP_KERNEL);
2918c2ecf20Sopenharmony_ci		if (!buf) {
2928c2ecf20Sopenharmony_ci			ret = -ENOMEM;
2938c2ecf20Sopenharmony_ci			goto err_map_addr;
2948c2ecf20Sopenharmony_ci		}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci		memcpy_fromio(buf, src_addr, reg->size);
2978c2ecf20Sopenharmony_ci		memcpy_toio(dst_addr, buf, reg->size);
2988c2ecf20Sopenharmony_ci		kfree(buf);
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci	ktime_get_ts64(&end);
3018c2ecf20Sopenharmony_ci	pci_epf_test_print_rate("COPY", reg->size, &start, &end, use_dma);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cierr_map_addr:
3048c2ecf20Sopenharmony_ci	pci_epc_unmap_addr(epc, epf->func_no, dst_phys_addr);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cierr_dst_addr:
3078c2ecf20Sopenharmony_ci	pci_epc_mem_free_addr(epc, dst_phys_addr, dst_addr, reg->size);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cierr_src_map_addr:
3108c2ecf20Sopenharmony_ci	pci_epc_unmap_addr(epc, epf->func_no, src_phys_addr);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_cierr_src_addr:
3138c2ecf20Sopenharmony_ci	pci_epc_mem_free_addr(epc, src_phys_addr, src_addr, reg->size);
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_cierr:
3168c2ecf20Sopenharmony_ci	return ret;
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_cistatic int pci_epf_test_read(struct pci_epf_test *epf_test)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	int ret;
3228c2ecf20Sopenharmony_ci	void __iomem *src_addr;
3238c2ecf20Sopenharmony_ci	void *buf;
3248c2ecf20Sopenharmony_ci	u32 crc32;
3258c2ecf20Sopenharmony_ci	bool use_dma;
3268c2ecf20Sopenharmony_ci	phys_addr_t phys_addr;
3278c2ecf20Sopenharmony_ci	phys_addr_t dst_phys_addr;
3288c2ecf20Sopenharmony_ci	struct timespec64 start, end;
3298c2ecf20Sopenharmony_ci	struct pci_epf *epf = epf_test->epf;
3308c2ecf20Sopenharmony_ci	struct device *dev = &epf->dev;
3318c2ecf20Sopenharmony_ci	struct pci_epc *epc = epf->epc;
3328c2ecf20Sopenharmony_ci	struct device *dma_dev = epf->epc->dev.parent;
3338c2ecf20Sopenharmony_ci	enum pci_barno test_reg_bar = epf_test->test_reg_bar;
3348c2ecf20Sopenharmony_ci	struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	src_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size);
3378c2ecf20Sopenharmony_ci	if (!src_addr) {
3388c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to allocate address\n");
3398c2ecf20Sopenharmony_ci		reg->status = STATUS_SRC_ADDR_INVALID;
3408c2ecf20Sopenharmony_ci		ret = -ENOMEM;
3418c2ecf20Sopenharmony_ci		goto err;
3428c2ecf20Sopenharmony_ci	}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	ret = pci_epc_map_addr(epc, epf->func_no, phys_addr, reg->src_addr,
3458c2ecf20Sopenharmony_ci			       reg->size);
3468c2ecf20Sopenharmony_ci	if (ret) {
3478c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to map address\n");
3488c2ecf20Sopenharmony_ci		reg->status = STATUS_SRC_ADDR_INVALID;
3498c2ecf20Sopenharmony_ci		goto err_addr;
3508c2ecf20Sopenharmony_ci	}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	buf = kzalloc(reg->size, GFP_KERNEL);
3538c2ecf20Sopenharmony_ci	if (!buf) {
3548c2ecf20Sopenharmony_ci		ret = -ENOMEM;
3558c2ecf20Sopenharmony_ci		goto err_map_addr;
3568c2ecf20Sopenharmony_ci	}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	use_dma = !!(reg->flags & FLAG_USE_DMA);
3598c2ecf20Sopenharmony_ci	if (use_dma) {
3608c2ecf20Sopenharmony_ci		if (!epf_test->dma_supported) {
3618c2ecf20Sopenharmony_ci			dev_err(dev, "Cannot transfer data using DMA\n");
3628c2ecf20Sopenharmony_ci			ret = -EINVAL;
3638c2ecf20Sopenharmony_ci			goto err_dma_map;
3648c2ecf20Sopenharmony_ci		}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci		dst_phys_addr = dma_map_single(dma_dev, buf, reg->size,
3678c2ecf20Sopenharmony_ci					       DMA_FROM_DEVICE);
3688c2ecf20Sopenharmony_ci		if (dma_mapping_error(dma_dev, dst_phys_addr)) {
3698c2ecf20Sopenharmony_ci			dev_err(dev, "Failed to map destination buffer addr\n");
3708c2ecf20Sopenharmony_ci			ret = -ENOMEM;
3718c2ecf20Sopenharmony_ci			goto err_dma_map;
3728c2ecf20Sopenharmony_ci		}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci		ktime_get_ts64(&start);
3758c2ecf20Sopenharmony_ci		ret = pci_epf_test_data_transfer(epf_test, dst_phys_addr,
3768c2ecf20Sopenharmony_ci						 phys_addr, reg->size);
3778c2ecf20Sopenharmony_ci		if (ret)
3788c2ecf20Sopenharmony_ci			dev_err(dev, "Data transfer failed\n");
3798c2ecf20Sopenharmony_ci		ktime_get_ts64(&end);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci		dma_unmap_single(dma_dev, dst_phys_addr, reg->size,
3828c2ecf20Sopenharmony_ci				 DMA_FROM_DEVICE);
3838c2ecf20Sopenharmony_ci	} else {
3848c2ecf20Sopenharmony_ci		ktime_get_ts64(&start);
3858c2ecf20Sopenharmony_ci		memcpy_fromio(buf, src_addr, reg->size);
3868c2ecf20Sopenharmony_ci		ktime_get_ts64(&end);
3878c2ecf20Sopenharmony_ci	}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	pci_epf_test_print_rate("READ", reg->size, &start, &end, use_dma);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	crc32 = crc32_le(~0, buf, reg->size);
3928c2ecf20Sopenharmony_ci	if (crc32 != reg->checksum)
3938c2ecf20Sopenharmony_ci		ret = -EIO;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_cierr_dma_map:
3968c2ecf20Sopenharmony_ci	kfree(buf);
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_cierr_map_addr:
3998c2ecf20Sopenharmony_ci	pci_epc_unmap_addr(epc, epf->func_no, phys_addr);
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_cierr_addr:
4028c2ecf20Sopenharmony_ci	pci_epc_mem_free_addr(epc, phys_addr, src_addr, reg->size);
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_cierr:
4058c2ecf20Sopenharmony_ci	return ret;
4068c2ecf20Sopenharmony_ci}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_cistatic int pci_epf_test_write(struct pci_epf_test *epf_test)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	int ret;
4118c2ecf20Sopenharmony_ci	void __iomem *dst_addr;
4128c2ecf20Sopenharmony_ci	void *buf;
4138c2ecf20Sopenharmony_ci	bool use_dma;
4148c2ecf20Sopenharmony_ci	phys_addr_t phys_addr;
4158c2ecf20Sopenharmony_ci	phys_addr_t src_phys_addr;
4168c2ecf20Sopenharmony_ci	struct timespec64 start, end;
4178c2ecf20Sopenharmony_ci	struct pci_epf *epf = epf_test->epf;
4188c2ecf20Sopenharmony_ci	struct device *dev = &epf->dev;
4198c2ecf20Sopenharmony_ci	struct pci_epc *epc = epf->epc;
4208c2ecf20Sopenharmony_ci	struct device *dma_dev = epf->epc->dev.parent;
4218c2ecf20Sopenharmony_ci	enum pci_barno test_reg_bar = epf_test->test_reg_bar;
4228c2ecf20Sopenharmony_ci	struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	dst_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size);
4258c2ecf20Sopenharmony_ci	if (!dst_addr) {
4268c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to allocate address\n");
4278c2ecf20Sopenharmony_ci		reg->status = STATUS_DST_ADDR_INVALID;
4288c2ecf20Sopenharmony_ci		ret = -ENOMEM;
4298c2ecf20Sopenharmony_ci		goto err;
4308c2ecf20Sopenharmony_ci	}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	ret = pci_epc_map_addr(epc, epf->func_no, phys_addr, reg->dst_addr,
4338c2ecf20Sopenharmony_ci			       reg->size);
4348c2ecf20Sopenharmony_ci	if (ret) {
4358c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to map address\n");
4368c2ecf20Sopenharmony_ci		reg->status = STATUS_DST_ADDR_INVALID;
4378c2ecf20Sopenharmony_ci		goto err_addr;
4388c2ecf20Sopenharmony_ci	}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	buf = kzalloc(reg->size, GFP_KERNEL);
4418c2ecf20Sopenharmony_ci	if (!buf) {
4428c2ecf20Sopenharmony_ci		ret = -ENOMEM;
4438c2ecf20Sopenharmony_ci		goto err_map_addr;
4448c2ecf20Sopenharmony_ci	}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	get_random_bytes(buf, reg->size);
4478c2ecf20Sopenharmony_ci	reg->checksum = crc32_le(~0, buf, reg->size);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	use_dma = !!(reg->flags & FLAG_USE_DMA);
4508c2ecf20Sopenharmony_ci	if (use_dma) {
4518c2ecf20Sopenharmony_ci		if (!epf_test->dma_supported) {
4528c2ecf20Sopenharmony_ci			dev_err(dev, "Cannot transfer data using DMA\n");
4538c2ecf20Sopenharmony_ci			ret = -EINVAL;
4548c2ecf20Sopenharmony_ci			goto err_dma_map;
4558c2ecf20Sopenharmony_ci		}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci		src_phys_addr = dma_map_single(dma_dev, buf, reg->size,
4588c2ecf20Sopenharmony_ci					       DMA_TO_DEVICE);
4598c2ecf20Sopenharmony_ci		if (dma_mapping_error(dma_dev, src_phys_addr)) {
4608c2ecf20Sopenharmony_ci			dev_err(dev, "Failed to map source buffer addr\n");
4618c2ecf20Sopenharmony_ci			ret = -ENOMEM;
4628c2ecf20Sopenharmony_ci			goto err_dma_map;
4638c2ecf20Sopenharmony_ci		}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci		ktime_get_ts64(&start);
4668c2ecf20Sopenharmony_ci		ret = pci_epf_test_data_transfer(epf_test, phys_addr,
4678c2ecf20Sopenharmony_ci						 src_phys_addr, reg->size);
4688c2ecf20Sopenharmony_ci		if (ret)
4698c2ecf20Sopenharmony_ci			dev_err(dev, "Data transfer failed\n");
4708c2ecf20Sopenharmony_ci		ktime_get_ts64(&end);
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci		dma_unmap_single(dma_dev, src_phys_addr, reg->size,
4738c2ecf20Sopenharmony_ci				 DMA_TO_DEVICE);
4748c2ecf20Sopenharmony_ci	} else {
4758c2ecf20Sopenharmony_ci		ktime_get_ts64(&start);
4768c2ecf20Sopenharmony_ci		memcpy_toio(dst_addr, buf, reg->size);
4778c2ecf20Sopenharmony_ci		ktime_get_ts64(&end);
4788c2ecf20Sopenharmony_ci	}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	pci_epf_test_print_rate("WRITE", reg->size, &start, &end, use_dma);
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	/*
4838c2ecf20Sopenharmony_ci	 * wait 1ms inorder for the write to complete. Without this delay L3
4848c2ecf20Sopenharmony_ci	 * error in observed in the host system.
4858c2ecf20Sopenharmony_ci	 */
4868c2ecf20Sopenharmony_ci	usleep_range(1000, 2000);
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_cierr_dma_map:
4898c2ecf20Sopenharmony_ci	kfree(buf);
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_cierr_map_addr:
4928c2ecf20Sopenharmony_ci	pci_epc_unmap_addr(epc, epf->func_no, phys_addr);
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_cierr_addr:
4958c2ecf20Sopenharmony_ci	pci_epc_mem_free_addr(epc, phys_addr, dst_addr, reg->size);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_cierr:
4988c2ecf20Sopenharmony_ci	return ret;
4998c2ecf20Sopenharmony_ci}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_cistatic void pci_epf_test_raise_irq(struct pci_epf_test *epf_test, u8 irq_type,
5028c2ecf20Sopenharmony_ci				   u16 irq)
5038c2ecf20Sopenharmony_ci{
5048c2ecf20Sopenharmony_ci	struct pci_epf *epf = epf_test->epf;
5058c2ecf20Sopenharmony_ci	struct device *dev = &epf->dev;
5068c2ecf20Sopenharmony_ci	struct pci_epc *epc = epf->epc;
5078c2ecf20Sopenharmony_ci	enum pci_barno test_reg_bar = epf_test->test_reg_bar;
5088c2ecf20Sopenharmony_ci	struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	reg->status |= STATUS_IRQ_RAISED;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	switch (irq_type) {
5138c2ecf20Sopenharmony_ci	case IRQ_TYPE_LEGACY:
5148c2ecf20Sopenharmony_ci		pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_LEGACY, 0);
5158c2ecf20Sopenharmony_ci		break;
5168c2ecf20Sopenharmony_ci	case IRQ_TYPE_MSI:
5178c2ecf20Sopenharmony_ci		pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSI, irq);
5188c2ecf20Sopenharmony_ci		break;
5198c2ecf20Sopenharmony_ci	case IRQ_TYPE_MSIX:
5208c2ecf20Sopenharmony_ci		pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSIX, irq);
5218c2ecf20Sopenharmony_ci		break;
5228c2ecf20Sopenharmony_ci	default:
5238c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to raise IRQ, unknown type\n");
5248c2ecf20Sopenharmony_ci		break;
5258c2ecf20Sopenharmony_ci	}
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_cistatic void pci_epf_test_cmd_handler(struct work_struct *work)
5298c2ecf20Sopenharmony_ci{
5308c2ecf20Sopenharmony_ci	int ret;
5318c2ecf20Sopenharmony_ci	int count;
5328c2ecf20Sopenharmony_ci	u32 command;
5338c2ecf20Sopenharmony_ci	struct pci_epf_test *epf_test = container_of(work, struct pci_epf_test,
5348c2ecf20Sopenharmony_ci						     cmd_handler.work);
5358c2ecf20Sopenharmony_ci	struct pci_epf *epf = epf_test->epf;
5368c2ecf20Sopenharmony_ci	struct device *dev = &epf->dev;
5378c2ecf20Sopenharmony_ci	struct pci_epc *epc = epf->epc;
5388c2ecf20Sopenharmony_ci	enum pci_barno test_reg_bar = epf_test->test_reg_bar;
5398c2ecf20Sopenharmony_ci	struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	command = reg->command;
5428c2ecf20Sopenharmony_ci	if (!command)
5438c2ecf20Sopenharmony_ci		goto reset_handler;
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	reg->command = 0;
5468c2ecf20Sopenharmony_ci	reg->status = 0;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	if (reg->irq_type > IRQ_TYPE_MSIX) {
5498c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to detect IRQ type\n");
5508c2ecf20Sopenharmony_ci		goto reset_handler;
5518c2ecf20Sopenharmony_ci	}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	if (command & COMMAND_RAISE_LEGACY_IRQ) {
5548c2ecf20Sopenharmony_ci		reg->status = STATUS_IRQ_RAISED;
5558c2ecf20Sopenharmony_ci		pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_LEGACY, 0);
5568c2ecf20Sopenharmony_ci		goto reset_handler;
5578c2ecf20Sopenharmony_ci	}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	if (command & COMMAND_WRITE) {
5608c2ecf20Sopenharmony_ci		ret = pci_epf_test_write(epf_test);
5618c2ecf20Sopenharmony_ci		if (ret)
5628c2ecf20Sopenharmony_ci			reg->status |= STATUS_WRITE_FAIL;
5638c2ecf20Sopenharmony_ci		else
5648c2ecf20Sopenharmony_ci			reg->status |= STATUS_WRITE_SUCCESS;
5658c2ecf20Sopenharmony_ci		pci_epf_test_raise_irq(epf_test, reg->irq_type,
5668c2ecf20Sopenharmony_ci				       reg->irq_number);
5678c2ecf20Sopenharmony_ci		goto reset_handler;
5688c2ecf20Sopenharmony_ci	}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	if (command & COMMAND_READ) {
5718c2ecf20Sopenharmony_ci		ret = pci_epf_test_read(epf_test);
5728c2ecf20Sopenharmony_ci		if (!ret)
5738c2ecf20Sopenharmony_ci			reg->status |= STATUS_READ_SUCCESS;
5748c2ecf20Sopenharmony_ci		else
5758c2ecf20Sopenharmony_ci			reg->status |= STATUS_READ_FAIL;
5768c2ecf20Sopenharmony_ci		pci_epf_test_raise_irq(epf_test, reg->irq_type,
5778c2ecf20Sopenharmony_ci				       reg->irq_number);
5788c2ecf20Sopenharmony_ci		goto reset_handler;
5798c2ecf20Sopenharmony_ci	}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	if (command & COMMAND_COPY) {
5828c2ecf20Sopenharmony_ci		ret = pci_epf_test_copy(epf_test);
5838c2ecf20Sopenharmony_ci		if (!ret)
5848c2ecf20Sopenharmony_ci			reg->status |= STATUS_COPY_SUCCESS;
5858c2ecf20Sopenharmony_ci		else
5868c2ecf20Sopenharmony_ci			reg->status |= STATUS_COPY_FAIL;
5878c2ecf20Sopenharmony_ci		pci_epf_test_raise_irq(epf_test, reg->irq_type,
5888c2ecf20Sopenharmony_ci				       reg->irq_number);
5898c2ecf20Sopenharmony_ci		goto reset_handler;
5908c2ecf20Sopenharmony_ci	}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	if (command & COMMAND_RAISE_MSI_IRQ) {
5938c2ecf20Sopenharmony_ci		count = pci_epc_get_msi(epc, epf->func_no);
5948c2ecf20Sopenharmony_ci		if (reg->irq_number > count || count <= 0)
5958c2ecf20Sopenharmony_ci			goto reset_handler;
5968c2ecf20Sopenharmony_ci		reg->status = STATUS_IRQ_RAISED;
5978c2ecf20Sopenharmony_ci		pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSI,
5988c2ecf20Sopenharmony_ci				  reg->irq_number);
5998c2ecf20Sopenharmony_ci		goto reset_handler;
6008c2ecf20Sopenharmony_ci	}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	if (command & COMMAND_RAISE_MSIX_IRQ) {
6038c2ecf20Sopenharmony_ci		count = pci_epc_get_msix(epc, epf->func_no);
6048c2ecf20Sopenharmony_ci		if (reg->irq_number > count || count <= 0)
6058c2ecf20Sopenharmony_ci			goto reset_handler;
6068c2ecf20Sopenharmony_ci		reg->status = STATUS_IRQ_RAISED;
6078c2ecf20Sopenharmony_ci		pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSIX,
6088c2ecf20Sopenharmony_ci				  reg->irq_number);
6098c2ecf20Sopenharmony_ci		goto reset_handler;
6108c2ecf20Sopenharmony_ci	}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_cireset_handler:
6138c2ecf20Sopenharmony_ci	queue_delayed_work(kpcitest_workqueue, &epf_test->cmd_handler,
6148c2ecf20Sopenharmony_ci			   msecs_to_jiffies(1));
6158c2ecf20Sopenharmony_ci}
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_cistatic void pci_epf_test_unbind(struct pci_epf *epf)
6188c2ecf20Sopenharmony_ci{
6198c2ecf20Sopenharmony_ci	struct pci_epf_test *epf_test = epf_get_drvdata(epf);
6208c2ecf20Sopenharmony_ci	struct pci_epc *epc = epf->epc;
6218c2ecf20Sopenharmony_ci	struct pci_epf_bar *epf_bar;
6228c2ecf20Sopenharmony_ci	int bar;
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	cancel_delayed_work(&epf_test->cmd_handler);
6258c2ecf20Sopenharmony_ci	pci_epf_test_clean_dma_chan(epf_test);
6268c2ecf20Sopenharmony_ci	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
6278c2ecf20Sopenharmony_ci		epf_bar = &epf->bar[bar];
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci		if (epf_test->reg[bar]) {
6308c2ecf20Sopenharmony_ci			pci_epc_clear_bar(epc, epf->func_no, epf_bar);
6318c2ecf20Sopenharmony_ci			pci_epf_free_space(epf, epf_test->reg[bar], bar);
6328c2ecf20Sopenharmony_ci		}
6338c2ecf20Sopenharmony_ci	}
6348c2ecf20Sopenharmony_ci}
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_cistatic int pci_epf_test_set_bar(struct pci_epf *epf)
6378c2ecf20Sopenharmony_ci{
6388c2ecf20Sopenharmony_ci	int bar, add;
6398c2ecf20Sopenharmony_ci	int ret;
6408c2ecf20Sopenharmony_ci	struct pci_epf_bar *epf_bar;
6418c2ecf20Sopenharmony_ci	struct pci_epc *epc = epf->epc;
6428c2ecf20Sopenharmony_ci	struct device *dev = &epf->dev;
6438c2ecf20Sopenharmony_ci	struct pci_epf_test *epf_test = epf_get_drvdata(epf);
6448c2ecf20Sopenharmony_ci	enum pci_barno test_reg_bar = epf_test->test_reg_bar;
6458c2ecf20Sopenharmony_ci	const struct pci_epc_features *epc_features;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	epc_features = epf_test->epc_features;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	for (bar = 0; bar < PCI_STD_NUM_BARS; bar += add) {
6508c2ecf20Sopenharmony_ci		epf_bar = &epf->bar[bar];
6518c2ecf20Sopenharmony_ci		/*
6528c2ecf20Sopenharmony_ci		 * pci_epc_set_bar() sets PCI_BASE_ADDRESS_MEM_TYPE_64
6538c2ecf20Sopenharmony_ci		 * if the specific implementation required a 64-bit BAR,
6548c2ecf20Sopenharmony_ci		 * even if we only requested a 32-bit BAR.
6558c2ecf20Sopenharmony_ci		 */
6568c2ecf20Sopenharmony_ci		add = (epf_bar->flags & PCI_BASE_ADDRESS_MEM_TYPE_64) ? 2 : 1;
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci		if (!!(epc_features->reserved_bar & (1 << bar)))
6598c2ecf20Sopenharmony_ci			continue;
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci		ret = pci_epc_set_bar(epc, epf->func_no, epf_bar);
6628c2ecf20Sopenharmony_ci		if (ret) {
6638c2ecf20Sopenharmony_ci			pci_epf_free_space(epf, epf_test->reg[bar], bar);
6648c2ecf20Sopenharmony_ci			dev_err(dev, "Failed to set BAR%d\n", bar);
6658c2ecf20Sopenharmony_ci			if (bar == test_reg_bar)
6668c2ecf20Sopenharmony_ci				return ret;
6678c2ecf20Sopenharmony_ci		}
6688c2ecf20Sopenharmony_ci	}
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	return 0;
6718c2ecf20Sopenharmony_ci}
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_cistatic int pci_epf_test_core_init(struct pci_epf *epf)
6748c2ecf20Sopenharmony_ci{
6758c2ecf20Sopenharmony_ci	struct pci_epf_test *epf_test = epf_get_drvdata(epf);
6768c2ecf20Sopenharmony_ci	struct pci_epf_header *header = epf->header;
6778c2ecf20Sopenharmony_ci	const struct pci_epc_features *epc_features;
6788c2ecf20Sopenharmony_ci	struct pci_epc *epc = epf->epc;
6798c2ecf20Sopenharmony_ci	struct device *dev = &epf->dev;
6808c2ecf20Sopenharmony_ci	bool msix_capable = false;
6818c2ecf20Sopenharmony_ci	bool msi_capable = true;
6828c2ecf20Sopenharmony_ci	int ret;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	epc_features = pci_epc_get_features(epc, epf->func_no);
6858c2ecf20Sopenharmony_ci	if (epc_features) {
6868c2ecf20Sopenharmony_ci		msix_capable = epc_features->msix_capable;
6878c2ecf20Sopenharmony_ci		msi_capable = epc_features->msi_capable;
6888c2ecf20Sopenharmony_ci	}
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	ret = pci_epc_write_header(epc, epf->func_no, header);
6918c2ecf20Sopenharmony_ci	if (ret) {
6928c2ecf20Sopenharmony_ci		dev_err(dev, "Configuration header write failed\n");
6938c2ecf20Sopenharmony_ci		return ret;
6948c2ecf20Sopenharmony_ci	}
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	ret = pci_epf_test_set_bar(epf);
6978c2ecf20Sopenharmony_ci	if (ret)
6988c2ecf20Sopenharmony_ci		return ret;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	if (msi_capable) {
7018c2ecf20Sopenharmony_ci		ret = pci_epc_set_msi(epc, epf->func_no, epf->msi_interrupts);
7028c2ecf20Sopenharmony_ci		if (ret) {
7038c2ecf20Sopenharmony_ci			dev_err(dev, "MSI configuration failed\n");
7048c2ecf20Sopenharmony_ci			return ret;
7058c2ecf20Sopenharmony_ci		}
7068c2ecf20Sopenharmony_ci	}
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	if (msix_capable) {
7098c2ecf20Sopenharmony_ci		ret = pci_epc_set_msix(epc, epf->func_no, epf->msix_interrupts,
7108c2ecf20Sopenharmony_ci				       epf_test->test_reg_bar,
7118c2ecf20Sopenharmony_ci				       epf_test->msix_table_offset);
7128c2ecf20Sopenharmony_ci		if (ret) {
7138c2ecf20Sopenharmony_ci			dev_err(dev, "MSI-X configuration failed\n");
7148c2ecf20Sopenharmony_ci			return ret;
7158c2ecf20Sopenharmony_ci		}
7168c2ecf20Sopenharmony_ci	}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	return 0;
7198c2ecf20Sopenharmony_ci}
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_cistatic int pci_epf_test_notifier(struct notifier_block *nb, unsigned long val,
7228c2ecf20Sopenharmony_ci				 void *data)
7238c2ecf20Sopenharmony_ci{
7248c2ecf20Sopenharmony_ci	struct pci_epf *epf = container_of(nb, struct pci_epf, nb);
7258c2ecf20Sopenharmony_ci	struct pci_epf_test *epf_test = epf_get_drvdata(epf);
7268c2ecf20Sopenharmony_ci	int ret;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	switch (val) {
7298c2ecf20Sopenharmony_ci	case CORE_INIT:
7308c2ecf20Sopenharmony_ci		ret = pci_epf_test_core_init(epf);
7318c2ecf20Sopenharmony_ci		if (ret)
7328c2ecf20Sopenharmony_ci			return NOTIFY_BAD;
7338c2ecf20Sopenharmony_ci		break;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	case LINK_UP:
7368c2ecf20Sopenharmony_ci		queue_delayed_work(kpcitest_workqueue, &epf_test->cmd_handler,
7378c2ecf20Sopenharmony_ci				   msecs_to_jiffies(1));
7388c2ecf20Sopenharmony_ci		break;
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	default:
7418c2ecf20Sopenharmony_ci		dev_err(&epf->dev, "Invalid EPF test notifier event\n");
7428c2ecf20Sopenharmony_ci		return NOTIFY_BAD;
7438c2ecf20Sopenharmony_ci	}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	return NOTIFY_OK;
7468c2ecf20Sopenharmony_ci}
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_cistatic int pci_epf_test_alloc_space(struct pci_epf *epf)
7498c2ecf20Sopenharmony_ci{
7508c2ecf20Sopenharmony_ci	struct pci_epf_test *epf_test = epf_get_drvdata(epf);
7518c2ecf20Sopenharmony_ci	struct device *dev = &epf->dev;
7528c2ecf20Sopenharmony_ci	struct pci_epf_bar *epf_bar;
7538c2ecf20Sopenharmony_ci	size_t msix_table_size = 0;
7548c2ecf20Sopenharmony_ci	size_t test_reg_bar_size;
7558c2ecf20Sopenharmony_ci	size_t pba_size = 0;
7568c2ecf20Sopenharmony_ci	bool msix_capable;
7578c2ecf20Sopenharmony_ci	void *base;
7588c2ecf20Sopenharmony_ci	int bar, add;
7598c2ecf20Sopenharmony_ci	enum pci_barno test_reg_bar = epf_test->test_reg_bar;
7608c2ecf20Sopenharmony_ci	const struct pci_epc_features *epc_features;
7618c2ecf20Sopenharmony_ci	size_t test_reg_size;
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	epc_features = epf_test->epc_features;
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	test_reg_bar_size = ALIGN(sizeof(struct pci_epf_test_reg), 128);
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	msix_capable = epc_features->msix_capable;
7688c2ecf20Sopenharmony_ci	if (msix_capable) {
7698c2ecf20Sopenharmony_ci		msix_table_size = PCI_MSIX_ENTRY_SIZE * epf->msix_interrupts;
7708c2ecf20Sopenharmony_ci		epf_test->msix_table_offset = test_reg_bar_size;
7718c2ecf20Sopenharmony_ci		/* Align to QWORD or 8 Bytes */
7728c2ecf20Sopenharmony_ci		pba_size = ALIGN(DIV_ROUND_UP(epf->msix_interrupts, 8), 8);
7738c2ecf20Sopenharmony_ci	}
7748c2ecf20Sopenharmony_ci	test_reg_size = test_reg_bar_size + msix_table_size + pba_size;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	if (epc_features->bar_fixed_size[test_reg_bar]) {
7778c2ecf20Sopenharmony_ci		if (test_reg_size > bar_size[test_reg_bar])
7788c2ecf20Sopenharmony_ci			return -ENOMEM;
7798c2ecf20Sopenharmony_ci		test_reg_size = bar_size[test_reg_bar];
7808c2ecf20Sopenharmony_ci	}
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	base = pci_epf_alloc_space(epf, test_reg_size, test_reg_bar,
7838c2ecf20Sopenharmony_ci				   epc_features->align);
7848c2ecf20Sopenharmony_ci	if (!base) {
7858c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to allocated register space\n");
7868c2ecf20Sopenharmony_ci		return -ENOMEM;
7878c2ecf20Sopenharmony_ci	}
7888c2ecf20Sopenharmony_ci	epf_test->reg[test_reg_bar] = base;
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	for (bar = 0; bar < PCI_STD_NUM_BARS; bar += add) {
7918c2ecf20Sopenharmony_ci		epf_bar = &epf->bar[bar];
7928c2ecf20Sopenharmony_ci		add = (epf_bar->flags & PCI_BASE_ADDRESS_MEM_TYPE_64) ? 2 : 1;
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci		if (bar == test_reg_bar)
7958c2ecf20Sopenharmony_ci			continue;
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci		if (!!(epc_features->reserved_bar & (1 << bar)))
7988c2ecf20Sopenharmony_ci			continue;
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci		base = pci_epf_alloc_space(epf, bar_size[bar], bar,
8018c2ecf20Sopenharmony_ci					   epc_features->align);
8028c2ecf20Sopenharmony_ci		if (!base)
8038c2ecf20Sopenharmony_ci			dev_err(dev, "Failed to allocate space for BAR%d\n",
8048c2ecf20Sopenharmony_ci				bar);
8058c2ecf20Sopenharmony_ci		epf_test->reg[bar] = base;
8068c2ecf20Sopenharmony_ci	}
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	return 0;
8098c2ecf20Sopenharmony_ci}
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_cistatic void pci_epf_configure_bar(struct pci_epf *epf,
8128c2ecf20Sopenharmony_ci				  const struct pci_epc_features *epc_features)
8138c2ecf20Sopenharmony_ci{
8148c2ecf20Sopenharmony_ci	struct pci_epf_bar *epf_bar;
8158c2ecf20Sopenharmony_ci	bool bar_fixed_64bit;
8168c2ecf20Sopenharmony_ci	int i;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
8198c2ecf20Sopenharmony_ci		epf_bar = &epf->bar[i];
8208c2ecf20Sopenharmony_ci		bar_fixed_64bit = !!(epc_features->bar_fixed_64bit & (1 << i));
8218c2ecf20Sopenharmony_ci		if (bar_fixed_64bit)
8228c2ecf20Sopenharmony_ci			epf_bar->flags |= PCI_BASE_ADDRESS_MEM_TYPE_64;
8238c2ecf20Sopenharmony_ci		if (epc_features->bar_fixed_size[i])
8248c2ecf20Sopenharmony_ci			bar_size[i] = epc_features->bar_fixed_size[i];
8258c2ecf20Sopenharmony_ci	}
8268c2ecf20Sopenharmony_ci}
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_cistatic int pci_epf_test_bind(struct pci_epf *epf)
8298c2ecf20Sopenharmony_ci{
8308c2ecf20Sopenharmony_ci	int ret;
8318c2ecf20Sopenharmony_ci	struct pci_epf_test *epf_test = epf_get_drvdata(epf);
8328c2ecf20Sopenharmony_ci	const struct pci_epc_features *epc_features;
8338c2ecf20Sopenharmony_ci	enum pci_barno test_reg_bar = BAR_0;
8348c2ecf20Sopenharmony_ci	struct pci_epc *epc = epf->epc;
8358c2ecf20Sopenharmony_ci	bool linkup_notifier = false;
8368c2ecf20Sopenharmony_ci	bool core_init_notifier = false;
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(!epc))
8398c2ecf20Sopenharmony_ci		return -EINVAL;
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	epc_features = pci_epc_get_features(epc, epf->func_no);
8428c2ecf20Sopenharmony_ci	if (!epc_features) {
8438c2ecf20Sopenharmony_ci		dev_err(&epf->dev, "epc_features not implemented\n");
8448c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
8458c2ecf20Sopenharmony_ci	}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	linkup_notifier = epc_features->linkup_notifier;
8488c2ecf20Sopenharmony_ci	core_init_notifier = epc_features->core_init_notifier;
8498c2ecf20Sopenharmony_ci	test_reg_bar = pci_epc_get_first_free_bar(epc_features);
8508c2ecf20Sopenharmony_ci	if (test_reg_bar < 0)
8518c2ecf20Sopenharmony_ci		return -EINVAL;
8528c2ecf20Sopenharmony_ci	pci_epf_configure_bar(epf, epc_features);
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	epf_test->test_reg_bar = test_reg_bar;
8558c2ecf20Sopenharmony_ci	epf_test->epc_features = epc_features;
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	ret = pci_epf_test_alloc_space(epf);
8588c2ecf20Sopenharmony_ci	if (ret)
8598c2ecf20Sopenharmony_ci		return ret;
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	if (!core_init_notifier) {
8628c2ecf20Sopenharmony_ci		ret = pci_epf_test_core_init(epf);
8638c2ecf20Sopenharmony_ci		if (ret)
8648c2ecf20Sopenharmony_ci			return ret;
8658c2ecf20Sopenharmony_ci	}
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	epf_test->dma_supported = true;
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	ret = pci_epf_test_init_dma_chan(epf_test);
8708c2ecf20Sopenharmony_ci	if (ret)
8718c2ecf20Sopenharmony_ci		epf_test->dma_supported = false;
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci	if (linkup_notifier || core_init_notifier) {
8748c2ecf20Sopenharmony_ci		epf->nb.notifier_call = pci_epf_test_notifier;
8758c2ecf20Sopenharmony_ci		pci_epc_register_notifier(epc, &epf->nb);
8768c2ecf20Sopenharmony_ci	} else {
8778c2ecf20Sopenharmony_ci		queue_work(kpcitest_workqueue, &epf_test->cmd_handler.work);
8788c2ecf20Sopenharmony_ci	}
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	return 0;
8818c2ecf20Sopenharmony_ci}
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_cistatic const struct pci_epf_device_id pci_epf_test_ids[] = {
8848c2ecf20Sopenharmony_ci	{
8858c2ecf20Sopenharmony_ci		.name = "pci_epf_test",
8868c2ecf20Sopenharmony_ci	},
8878c2ecf20Sopenharmony_ci	{},
8888c2ecf20Sopenharmony_ci};
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_cistatic int pci_epf_test_probe(struct pci_epf *epf)
8918c2ecf20Sopenharmony_ci{
8928c2ecf20Sopenharmony_ci	struct pci_epf_test *epf_test;
8938c2ecf20Sopenharmony_ci	struct device *dev = &epf->dev;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	epf_test = devm_kzalloc(dev, sizeof(*epf_test), GFP_KERNEL);
8968c2ecf20Sopenharmony_ci	if (!epf_test)
8978c2ecf20Sopenharmony_ci		return -ENOMEM;
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	epf->header = &test_header;
9008c2ecf20Sopenharmony_ci	epf_test->epf = epf;
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&epf_test->cmd_handler, pci_epf_test_cmd_handler);
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	epf_set_drvdata(epf, epf_test);
9058c2ecf20Sopenharmony_ci	return 0;
9068c2ecf20Sopenharmony_ci}
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_cistatic struct pci_epf_ops ops = {
9098c2ecf20Sopenharmony_ci	.unbind	= pci_epf_test_unbind,
9108c2ecf20Sopenharmony_ci	.bind	= pci_epf_test_bind,
9118c2ecf20Sopenharmony_ci};
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_cistatic struct pci_epf_driver test_driver = {
9148c2ecf20Sopenharmony_ci	.driver.name	= "pci_epf_test",
9158c2ecf20Sopenharmony_ci	.probe		= pci_epf_test_probe,
9168c2ecf20Sopenharmony_ci	.id_table	= pci_epf_test_ids,
9178c2ecf20Sopenharmony_ci	.ops		= &ops,
9188c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
9198c2ecf20Sopenharmony_ci};
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_cistatic int __init pci_epf_test_init(void)
9228c2ecf20Sopenharmony_ci{
9238c2ecf20Sopenharmony_ci	int ret;
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	kpcitest_workqueue = alloc_workqueue("kpcitest",
9268c2ecf20Sopenharmony_ci					     WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
9278c2ecf20Sopenharmony_ci	if (!kpcitest_workqueue) {
9288c2ecf20Sopenharmony_ci		pr_err("Failed to allocate the kpcitest work queue\n");
9298c2ecf20Sopenharmony_ci		return -ENOMEM;
9308c2ecf20Sopenharmony_ci	}
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	ret = pci_epf_register_driver(&test_driver);
9338c2ecf20Sopenharmony_ci	if (ret) {
9348c2ecf20Sopenharmony_ci		destroy_workqueue(kpcitest_workqueue);
9358c2ecf20Sopenharmony_ci		pr_err("Failed to register pci epf test driver --> %d\n", ret);
9368c2ecf20Sopenharmony_ci		return ret;
9378c2ecf20Sopenharmony_ci	}
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	return 0;
9408c2ecf20Sopenharmony_ci}
9418c2ecf20Sopenharmony_cimodule_init(pci_epf_test_init);
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_cistatic void __exit pci_epf_test_exit(void)
9448c2ecf20Sopenharmony_ci{
9458c2ecf20Sopenharmony_ci	if (kpcitest_workqueue)
9468c2ecf20Sopenharmony_ci		destroy_workqueue(kpcitest_workqueue);
9478c2ecf20Sopenharmony_ci	pci_epf_unregister_driver(&test_driver);
9488c2ecf20Sopenharmony_ci}
9498c2ecf20Sopenharmony_cimodule_exit(pci_epf_test_exit);
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PCI EPF TEST DRIVER");
9528c2ecf20Sopenharmony_ciMODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
9538c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
954