Spaces:
Runtime error
Runtime error
| /* | |
| * Edu PCI device. | |
| * | |
| * Copyright (C) 2016 Red Hat, Inc. | |
| * | |
| * Authors: | |
| * Peter Xu <peterx@redhat.com>, | |
| * | |
| * This work is licensed under the terms of the GNU LGPL, version 2 or | |
| * later. | |
| */ | |
| /* Return true if alive */ | |
| static inline bool edu_check_alive(struct pci_edu_dev *dev) | |
| { | |
| static uint32_t live_count = 1; | |
| uint32_t value; | |
| edu_reg_writel(dev, EDU_REG_ALIVE, live_count++); | |
| value = edu_reg_readl(dev, EDU_REG_ALIVE); | |
| return (live_count - 1 == ~value); | |
| } | |
| bool edu_init(struct pci_edu_dev *dev) | |
| { | |
| pcidevaddr_t dev_addr; | |
| dev_addr = pci_find_dev(PCI_VENDOR_ID_QEMU, PCI_DEVICE_ID_EDU); | |
| if (dev_addr == PCIDEVADDR_INVALID) | |
| return false; | |
| pci_dev_init(&dev->pci_dev, dev_addr); | |
| pci_enable_defaults(&dev->pci_dev); | |
| dev->reg_base = ioremap(dev->pci_dev.resource[EDU_BAR], PAGE_SIZE); | |
| assert(edu_check_alive(dev)); | |
| return true; | |
| } | |
| void edu_dma(struct pci_edu_dev *dev, iova_t iova, | |
| size_t size, unsigned int dev_offset, bool from_device) | |
| { | |
| uint64_t from, to; | |
| uint32_t cmd = EDU_CMD_DMA_START; | |
| assert(size <= EDU_DMA_SIZE_MAX); | |
| assert(dev_offset < EDU_DMA_SIZE_MAX); | |
| printf("edu device DMA start %s addr %#" PRIx64 " size %lu off %#x\n", | |
| from_device ? "FROM" : "TO", | |
| iova, (ulong)size, dev_offset); | |
| if (from_device) { | |
| from = dev_offset + EDU_DMA_START; | |
| to = iova; | |
| cmd |= EDU_CMD_DMA_FROM; | |
| } else { | |
| from = iova; | |
| to = EDU_DMA_START + dev_offset; | |
| cmd |= EDU_CMD_DMA_TO; | |
| } | |
| edu_reg_writeq(dev, EDU_REG_DMA_SRC, from); | |
| edu_reg_writeq(dev, EDU_REG_DMA_DST, to); | |
| edu_reg_writeq(dev, EDU_REG_DMA_COUNT, size); | |
| edu_reg_writel(dev, EDU_REG_DMA_CMD, cmd); | |
| /* Wait until DMA finished */ | |
| while (edu_reg_readl(dev, EDU_REG_DMA_CMD) & EDU_CMD_DMA_START) | |
| cpu_relax(); | |
| } | |