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