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 */ 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 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 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