From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44877) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bbruN-0001VB-Ft for qemu-devel@nongnu.org; Mon, 22 Aug 2016 12:17:09 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bbruL-0002fz-Px for qemu-devel@nongnu.org; Mon, 22 Aug 2016 12:17:07 -0400 Received: from mail-pf0-x230.google.com ([2607:f8b0:400e:c00::230]:35388) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bbruK-0002fO-C7 for qemu-devel@nongnu.org; Mon, 22 Aug 2016 12:17:05 -0400 Received: by mail-pf0-x230.google.com with SMTP id x72so33835595pfd.2 for ; Mon, 22 Aug 2016 09:17:03 -0700 (PDT) From: Prem Mallappa Date: Mon, 22 Aug 2016 21:47:37 +0530 Message-Id: <20160822161740.4252-7-prem.mallappa@broadcom.com> In-Reply-To: <20160822161740.4252-1-prem.mallappa@broadcom.com> References: <20160822161740.4252-1-prem.mallappa@broadcom.com> Subject: [Qemu-devel] [PATCH v2 6/9] [optional] hw: misc: added testdev for smmu List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Peter Maydell , "Edgar E . Iglesias" , qemu-devel@nongnu.org Cc: Prem Mallappa A simple PCI device which does DMA from 'src' to 'dst' given src_addr, dst_addr and size, and is used by unit test. uses pci_dma_read and pci_dma_write in a crude way but serves the purpose. Signed-off-by: Prem Mallappa --- hw/misc/Makefile.objs | 2 +- hw/misc/pci-testdev-smmu.c | 239 +++++++++++++++++++++++++++++++++++++++++++++ hw/misc/pci-testdev-smmu.h | 22 +++++ 3 files changed, 262 insertions(+), 1 deletion(-) create mode 100644 hw/misc/pci-testdev-smmu.c create mode 100644 hw/misc/pci-testdev-smmu.h diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index ffb49c1..fc34c5f 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -29,7 +29,6 @@ obj-$(CONFIG_IMX) += imx_ccm.o obj-$(CONFIG_IMX) += imx31_ccm.o obj-$(CONFIG_IMX) += imx25_ccm.o obj-$(CONFIG_IMX) += imx6_ccm.o -obj-$(CONFIG_IMX) += imx6_src.o obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o obj-$(CONFIG_MAINSTONE) += mst_fpga.o @@ -52,3 +51,4 @@ obj-$(CONFIG_PVPANIC) += pvpanic.o obj-$(CONFIG_EDU) += edu.o obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o obj-$(CONFIG_AUX) += aux.o +obj-$(CONFIG_ARM_SMMUV3) += pci-testdev-smmu.o diff --git a/hw/misc/pci-testdev-smmu.c b/hw/misc/pci-testdev-smmu.c new file mode 100644 index 0000000..b605912 --- /dev/null +++ b/hw/misc/pci-testdev-smmu.c @@ -0,0 +1,239 @@ +/* + * QEMU PCI test device + * + * Copyright (c) 2012 Red Hat Inc. + * Author: Michael S. Tsirkin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ +#include "qemu/osdep.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "qemu/event_notifier.h" + +#include "pci-testdev-smmu.h" + +/* + * pci-testdev-smmu: + * Simple PCIe device, to enable read and write from memory. + * Architecture: + * Following registers are supported. + * TST_COMMAND = 0x0 + * TST_STATUS = 0x4 + * TST_SRC_ADDRESS = 0x8 + * TST_SIZE = 0x10 + * TST_DST_ADDRESS = 0x18 + */ +#define PCI_TSTDEV_NREGS 0x10 + +/* + * TST_COMMAND Register bits + * OP[0] + * READ = 0x0 + * WRITE = 0x1 + */ + +struct RegInfo { + uint64_t data; + char *name; +}; +typedef struct RegInfo RegInfo; + +typedef struct PCITestDevState { + /*< private >*/ + PCIDevice dev; + /*< public >*/ + + MemoryRegion mmio; + RegInfo regs[PCI_TSTDEV_NREGS]; +} PCITestDevState; + +#define TYPE_PCI_TEST_DEV "pci-testdev-smmu" + +#define PCI_TEST_DEV(obj) \ + OBJECT_CHECK(PCITestDevState, (obj), TYPE_PCI_TEST_DEV) + +static void +pci_tstdev_reset(PCITestDevState *d) +{ + memset(d->regs, 0, sizeof(d->regs)); +} + +static inline void +pci_tstdev_write_reg(PCITestDevState *pdev, hwaddr addr, uint64_t val) +{ + RegInfo *reg = &pdev->regs[addr >> 2]; + reg->data = val; +} + +static inline uint32_t +pci_tstdev_read32_reg(PCITestDevState *pdev, hwaddr addr) +{ + RegInfo *reg = &pdev->regs[addr >> 2]; + return (uint32_t) reg->data; +} + +static inline uint64_t +pci_tstdev_read64_reg(PCITestDevState *pdev, hwaddr addr) +{ + RegInfo *reg = &pdev->regs[addr >> 2]; + return reg->data; +} + +static void +pci_tstdev_handle_cmd(PCITestDevState *pdev, hwaddr addr, uint64_t val, + unsigned _unused_size) +{ + uint64_t s = pci_tstdev_read64_reg(pdev, TST_REG_SRC_ADDR); + uint64_t d = pci_tstdev_read64_reg(pdev, TST_REG_DST_ADDR); + uint32_t size = pci_tstdev_read32_reg(pdev, TST_REG_SIZE); + uint8_t buf[128]; + + printf("+++++++++++++++++++++> src:%lx, dst:%lx size:%d\n", + s, d, size); + while (size) { + int nbytes = (size < sizeof(buf)) ? size: sizeof(buf); + int ret = 0; + printf("nbytes:%d\n", nbytes); + if (val & CMD_READ) { + printf("doing pci_dma_read\n"); + ret = pci_dma_read(&pdev->dev, s, (void*)buf, nbytes); + } + if (ret) + return; + + if (val & CMD_WRITE) { + printf("doing pci_dma_write\n"); + ret = pci_dma_write(&pdev->dev, d, (void*)buf, nbytes); + } + size -= nbytes; + s += nbytes; + d += nbytes; + } +} + +static void +pci_tstdev_mmio_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + PCITestDevState *d = opaque; + uint64_t lo; + + printf("=================> addr:%ld act:%d val:%lx reg_addr:%p\n", + addr, TST_REG_COMMAND, val, &d->regs[addr]); + //addr >>= 2; + switch (addr) { + case TST_REG_COMMAND: + printf("Calling command handler.....\n"); + pci_tstdev_handle_cmd(d, addr, val, size); + case TST_REG_SRC_ADDR: + case TST_REG_DST_ADDR: + case TST_REG_SIZE: + pci_tstdev_write_reg(d, addr, val); + break; + case TST_REG_SRC_ADDR + 4: + case TST_REG_DST_ADDR + 4: + lo = pci_tstdev_read32_reg(d, addr); + lo &= (0xffffffffULL << 32); + pci_tstdev_write_reg(d, addr, (val << 32) | lo); + break; + case TST_REG_STATUS: /* Read only reg */ + default: + printf("Unkown/RO register write\n"); + break; + } +} + +static uint64_t +pci_tstdev_mmio_read(void *opaque, hwaddr addr, unsigned size) +{ + PCITestDevState *d = opaque; + + switch (addr) { + case TST_REG_SRC_ADDR: + case TST_REG_DST_ADDR: + return pci_tstdev_read64_reg(d, addr); + } + + return pci_tstdev_read32_reg(d, addr); +} + +static const MemoryRegionOps pci_testdev_mmio_ops = { + .read = pci_tstdev_mmio_read, + .write = pci_tstdev_mmio_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + }, +}; + +static void pci_tstdev_realize(PCIDevice *pci_dev, Error **errp) +{ + PCITestDevState *d = PCI_TEST_DEV(pci_dev); + uint8_t *pci_conf; + + pci_conf = pci_dev->config; + + pci_conf[PCI_INTERRUPT_PIN] = 0; /* no interrupt pin */ + + memory_region_init_io(&d->mmio, OBJECT(d), &pci_testdev_mmio_ops, d, + "pci-testdev-smmu-mmio", 1 << 10); + + pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio); +} + +static void +pci_tstdev_uninit(PCIDevice *dev) +{ + PCITestDevState *d = PCI_TEST_DEV(dev); + + pci_tstdev_reset(d); +} + +static void qdev_pci_tstdev_reset(DeviceState *dev) +{ + PCITestDevState *d = PCI_TEST_DEV(dev); + pci_tstdev_reset(d); +} + +static void pci_tstdev_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->realize = pci_tstdev_realize; + k->exit = pci_tstdev_uninit; + k->vendor_id = PCI_VENDOR_ID_REDHAT; + k->device_id = PCI_DEVICE_ID_REDHAT_TEST; + k->revision = 0x00; + k->class_id = PCI_CLASS_OTHERS; + dc->desc = "PCI Test Device - for smmu"; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + dc->reset = qdev_pci_tstdev_reset; +} + +static const TypeInfo pci_tstdev_info = { + .name = TYPE_PCI_TEST_DEV, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCITestDevState), + .class_init = pci_tstdev_class_init, +}; + +static void pci_tstdev_register_types(void) +{ + type_register_static(&pci_tstdev_info); +} + +type_init(pci_tstdev_register_types) diff --git a/hw/misc/pci-testdev-smmu.h b/hw/misc/pci-testdev-smmu.h new file mode 100644 index 0000000..4a2d463 --- /dev/null +++ b/hw/misc/pci-testdev-smmu.h @@ -0,0 +1,22 @@ +#ifndef HW_MISC_PCI_TESTDEV_SMMU +#define HW_MISC_PCI_TESTDEV_SMMU + +enum reg { + TST_REG_COMMAND = 0x0, + TST_REG_STATUS = 0x4, + TST_REG_SRC_ADDR = 0x8, + TST_REG_SIZE = 0x10, + TST_REG_DST_ADDR = 0x18, + + TST_REG_LAST = 0x30, +}; + +#define CMD_READ 0x100 +#define CMD_WRITE 0x200 +#define CMD_RW (CMD_READ | CMD_WRITE) + +#define STATUS_OK (1 << 0) +#define STATUS_CMD_ERROR (1 << 1) +#define STATUS_CMD_INVALID (1 << 2) + +#endif -- 2.9.3