xref: /kvm-unit-tests/lib/pci-edu.c (revision fd6aada0dac74cf00e2d0b701362e1f89d2c28e3)
17f2a26cdSPeter Xu /*
27f2a26cdSPeter Xu  * Edu PCI device.
37f2a26cdSPeter Xu  *
47f2a26cdSPeter Xu  * Copyright (C) 2016 Red Hat, Inc.
57f2a26cdSPeter Xu  *
67f2a26cdSPeter Xu  * Authors:
77f2a26cdSPeter Xu  *   Peter Xu <peterx@redhat.com>,
87f2a26cdSPeter Xu  *
97f2a26cdSPeter Xu  * This work is licensed under the terms of the GNU LGPL, version 2 or
107f2a26cdSPeter Xu  * later.
117f2a26cdSPeter Xu  */
127f2a26cdSPeter Xu 
137f2a26cdSPeter Xu #include "pci-edu.h"
147f2a26cdSPeter Xu #include "asm/barrier.h"
157f2a26cdSPeter Xu 
167f2a26cdSPeter Xu /* Return true if alive */
edu_check_alive(struct pci_edu_dev * dev)177f2a26cdSPeter Xu static inline bool edu_check_alive(struct pci_edu_dev *dev)
187f2a26cdSPeter Xu {
197f2a26cdSPeter Xu 	static uint32_t live_count = 1;
207f2a26cdSPeter Xu 	uint32_t value;
217f2a26cdSPeter Xu 
227f2a26cdSPeter Xu 	edu_reg_writel(dev, EDU_REG_ALIVE, live_count++);
237f2a26cdSPeter Xu 	value = edu_reg_readl(dev, EDU_REG_ALIVE);
247f2a26cdSPeter Xu 	return (live_count - 1 == ~value);
257f2a26cdSPeter Xu }
267f2a26cdSPeter Xu 
edu_init(struct pci_edu_dev * dev)277f2a26cdSPeter Xu bool edu_init(struct pci_edu_dev *dev)
287f2a26cdSPeter Xu {
297f2a26cdSPeter Xu 	pcidevaddr_t dev_addr;
307f2a26cdSPeter Xu 
317f2a26cdSPeter Xu 	dev_addr = pci_find_dev(PCI_VENDOR_ID_QEMU, PCI_DEVICE_ID_EDU);
327f2a26cdSPeter Xu 	if (dev_addr == PCIDEVADDR_INVALID)
337f2a26cdSPeter Xu 		return false;
347f2a26cdSPeter Xu 
357f2a26cdSPeter Xu 	pci_dev_init(&dev->pci_dev, dev_addr);
367f2a26cdSPeter Xu 	pci_enable_defaults(&dev->pci_dev);
377f2a26cdSPeter Xu 	dev->reg_base = ioremap(dev->pci_dev.resource[EDU_BAR], PAGE_SIZE);
387f2a26cdSPeter Xu 	assert(edu_check_alive(dev));
397f2a26cdSPeter Xu 	return true;
407f2a26cdSPeter Xu }
417f2a26cdSPeter Xu 
edu_dma(struct pci_edu_dev * dev,iova_t iova,size_t size,unsigned int dev_offset,bool from_device)427f2a26cdSPeter Xu void edu_dma(struct pci_edu_dev *dev, iova_t iova,
437f2a26cdSPeter Xu 	     size_t size, unsigned int dev_offset, bool from_device)
447f2a26cdSPeter Xu {
457f2a26cdSPeter Xu 	uint64_t from, to;
467f2a26cdSPeter Xu 	uint32_t cmd = EDU_CMD_DMA_START;
477f2a26cdSPeter Xu 
487f2a26cdSPeter Xu 	assert(size <= EDU_DMA_SIZE_MAX);
497f2a26cdSPeter Xu 	assert(dev_offset < EDU_DMA_SIZE_MAX);
507f2a26cdSPeter Xu 
51*fd6aada0SRadim Krčmář 	printf("edu device DMA start %s addr %#" PRIx64 " size %lu off %#x\n",
527f2a26cdSPeter Xu 	       from_device ? "FROM" : "TO",
536faf839cSAndrew Jones 	       iova, (ulong)size, dev_offset);
547f2a26cdSPeter Xu 
557f2a26cdSPeter Xu 	if (from_device) {
567f2a26cdSPeter Xu 		from = dev_offset + EDU_DMA_START;
577f2a26cdSPeter Xu 		to = iova;
587f2a26cdSPeter Xu 		cmd |= EDU_CMD_DMA_FROM;
597f2a26cdSPeter Xu 	} else {
607f2a26cdSPeter Xu 		from = iova;
617f2a26cdSPeter Xu 		to = EDU_DMA_START + dev_offset;
627f2a26cdSPeter Xu 		cmd |= EDU_CMD_DMA_TO;
637f2a26cdSPeter Xu 	}
647f2a26cdSPeter Xu 
657f2a26cdSPeter Xu 	edu_reg_writeq(dev, EDU_REG_DMA_SRC, from);
667f2a26cdSPeter Xu 	edu_reg_writeq(dev, EDU_REG_DMA_DST, to);
677f2a26cdSPeter Xu 	edu_reg_writeq(dev, EDU_REG_DMA_COUNT, size);
687f2a26cdSPeter Xu 	edu_reg_writel(dev, EDU_REG_DMA_CMD, cmd);
697f2a26cdSPeter Xu 
707f2a26cdSPeter Xu 	/* Wait until DMA finished */
717f2a26cdSPeter Xu 	while (edu_reg_readl(dev, EDU_REG_DMA_CMD) & EDU_CMD_DMA_START)
727f2a26cdSPeter Xu 		cpu_relax();
737f2a26cdSPeter Xu }
74