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