xref: /kvm-unit-tests/lib/pci-edu.c (revision 7f2a26cd2172069c3873ce0cee3c7f7a39e6eb6a)
1*7f2a26cdSPeter Xu /*
2*7f2a26cdSPeter Xu  * Edu PCI device.
3*7f2a26cdSPeter Xu  *
4*7f2a26cdSPeter Xu  * Copyright (C) 2016 Red Hat, Inc.
5*7f2a26cdSPeter Xu  *
6*7f2a26cdSPeter Xu  * Authors:
7*7f2a26cdSPeter Xu  *   Peter Xu <peterx@redhat.com>,
8*7f2a26cdSPeter Xu  *
9*7f2a26cdSPeter Xu  * This work is licensed under the terms of the GNU LGPL, version 2 or
10*7f2a26cdSPeter Xu  * later.
11*7f2a26cdSPeter Xu  */
12*7f2a26cdSPeter Xu 
13*7f2a26cdSPeter Xu #include "pci-edu.h"
14*7f2a26cdSPeter Xu #include "asm/barrier.h"
15*7f2a26cdSPeter Xu 
16*7f2a26cdSPeter Xu /* Return true if alive */
17*7f2a26cdSPeter Xu static inline bool edu_check_alive(struct pci_edu_dev *dev)
18*7f2a26cdSPeter Xu {
19*7f2a26cdSPeter Xu 	static uint32_t live_count = 1;
20*7f2a26cdSPeter Xu 	uint32_t value;
21*7f2a26cdSPeter Xu 
22*7f2a26cdSPeter Xu 	edu_reg_writel(dev, EDU_REG_ALIVE, live_count++);
23*7f2a26cdSPeter Xu 	value = edu_reg_readl(dev, EDU_REG_ALIVE);
24*7f2a26cdSPeter Xu 	return (live_count - 1 == ~value);
25*7f2a26cdSPeter Xu }
26*7f2a26cdSPeter Xu 
27*7f2a26cdSPeter Xu bool edu_init(struct pci_edu_dev *dev)
28*7f2a26cdSPeter Xu {
29*7f2a26cdSPeter Xu 	pcidevaddr_t dev_addr;
30*7f2a26cdSPeter Xu 
31*7f2a26cdSPeter Xu 	dev_addr = pci_find_dev(PCI_VENDOR_ID_QEMU, PCI_DEVICE_ID_EDU);
32*7f2a26cdSPeter Xu 	if (dev_addr == PCIDEVADDR_INVALID)
33*7f2a26cdSPeter Xu 		return false;
34*7f2a26cdSPeter Xu 
35*7f2a26cdSPeter Xu 	pci_dev_init(&dev->pci_dev, dev_addr);
36*7f2a26cdSPeter Xu 	pci_enable_defaults(&dev->pci_dev);
37*7f2a26cdSPeter Xu 	dev->reg_base = ioremap(dev->pci_dev.resource[EDU_BAR], PAGE_SIZE);
38*7f2a26cdSPeter Xu 	assert(edu_check_alive(dev));
39*7f2a26cdSPeter Xu 	return true;
40*7f2a26cdSPeter Xu }
41*7f2a26cdSPeter Xu 
42*7f2a26cdSPeter Xu void edu_dma(struct pci_edu_dev *dev, iova_t iova,
43*7f2a26cdSPeter Xu 	     size_t size, unsigned int dev_offset, bool from_device)
44*7f2a26cdSPeter Xu {
45*7f2a26cdSPeter Xu 	uint64_t from, to;
46*7f2a26cdSPeter Xu 	uint32_t cmd = EDU_CMD_DMA_START;
47*7f2a26cdSPeter Xu 
48*7f2a26cdSPeter Xu 	assert(size <= EDU_DMA_SIZE_MAX);
49*7f2a26cdSPeter Xu 	assert(dev_offset < EDU_DMA_SIZE_MAX);
50*7f2a26cdSPeter Xu 
51*7f2a26cdSPeter Xu 	printf("edu device DMA start %s addr %p size 0x%lu off 0x%x\n",
52*7f2a26cdSPeter Xu 	       from_device ? "FROM" : "TO",
53*7f2a26cdSPeter Xu 	       (void *)iova, size, dev_offset);
54*7f2a26cdSPeter Xu 
55*7f2a26cdSPeter Xu 	if (from_device) {
56*7f2a26cdSPeter Xu 		from = dev_offset + EDU_DMA_START;
57*7f2a26cdSPeter Xu 		to = iova;
58*7f2a26cdSPeter Xu 		cmd |= EDU_CMD_DMA_FROM;
59*7f2a26cdSPeter Xu 	} else {
60*7f2a26cdSPeter Xu 		from = iova;
61*7f2a26cdSPeter Xu 		to = EDU_DMA_START + dev_offset;
62*7f2a26cdSPeter Xu 		cmd |= EDU_CMD_DMA_TO;
63*7f2a26cdSPeter Xu 	}
64*7f2a26cdSPeter Xu 
65*7f2a26cdSPeter Xu 	edu_reg_writeq(dev, EDU_REG_DMA_SRC, from);
66*7f2a26cdSPeter Xu 	edu_reg_writeq(dev, EDU_REG_DMA_DST, to);
67*7f2a26cdSPeter Xu 	edu_reg_writeq(dev, EDU_REG_DMA_COUNT, size);
68*7f2a26cdSPeter Xu 	edu_reg_writel(dev, EDU_REG_DMA_CMD, cmd);
69*7f2a26cdSPeter Xu 
70*7f2a26cdSPeter Xu 	/* Wait until DMA finished */
71*7f2a26cdSPeter Xu 	while (edu_reg_readl(dev, EDU_REG_DMA_CMD) & EDU_CMD_DMA_START)
72*7f2a26cdSPeter Xu 		cpu_relax();
73*7f2a26cdSPeter Xu }
74