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 */ 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 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 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*6faf839cSAndrew Jones printf("edu device DMA start %s addr 0x%" PRIx64 " size 0x%lu off 0x%x\n", 527f2a26cdSPeter Xu from_device ? "FROM" : "TO", 53*6faf839cSAndrew 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