From patchwork Wed Jul 16 08:47:34 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Jones X-Patchwork-Id: 4565591 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id BF3DBC0514 for ; Wed, 16 Jul 2014 08:49:02 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 9DF56201C7 for ; Wed, 16 Jul 2014 08:49:01 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 68DC02018E for ; Wed, 16 Jul 2014 08:49:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1760871AbaGPIsF (ORCPT ); Wed, 16 Jul 2014 04:48:05 -0400 Received: from mx1.redhat.com ([209.132.183.28]:11982 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757903AbaGPIr7 (ORCPT ); Wed, 16 Jul 2014 04:47:59 -0400 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s6G8lvII002098 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 16 Jul 2014 04:47:57 -0400 Received: from hawk.usersys.redhat.com (dhcp-1-116.brq.redhat.com [10.34.1.116]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id s6G8llvi029735; Wed, 16 Jul 2014 04:47:56 -0400 From: Andrew Jones To: kvmarm@lists.cs.columbia.edu, kvm@vger.kernel.org Cc: christoffer.dall@linaro.org, pbonzini@redhat.com Subject: [PATCH v7 05/14] add minimal virtio support for devtree virtio-mmio Date: Wed, 16 Jul 2014 10:47:34 +0200 Message-Id: <1405500463-20713-6-git-send-email-drjones@redhat.com> In-Reply-To: <1405500463-20713-1-git-send-email-drjones@redhat.com> References: <1405500463-20713-1-git-send-email-drjones@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Support the bare minimum of virtio to enable access to the virtio-mmio config space of a device. Currently this implementation must use a device tree to find the device. Signed-off-by: Andrew Jones Reviewed-by: Christoffer Dall --- v7: - s/alloc/calloc/ - split into virtio.[ch] and virtio-mmio.[ch] [Paolo Bonzini] - dump virtio_bind_busses table [Paolo Bonzini] v6: - switch to using alloc() - s/vmdev/vm_dev/ to be consistent with kernel naming - check for virtio magic in vm_dt_match v5: - use same virtio struct names as kernel - no need to alloc a new virtio_config_ops for each virtio device - use ioremap v4: - split from the virtio-testdev patch - search a table to "discover" that the device must be DT/virtio-mmio, which doesn't change anything, but looks less hacky than comments saying the device must be DT/virtio-mmio... - manage own pool of virtio-mmio pre-allocated device structures in order to avoid needing access to the heap --- lib/virtio-mmio.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/virtio-mmio.h | 47 +++++++++++++++++++++++ lib/virtio.c | 13 +++++++ lib/virtio.h | 74 ++++++++++++++++++++++++++++++++++++ 4 files changed, 245 insertions(+) create mode 100644 lib/virtio-mmio.c create mode 100644 lib/virtio-mmio.h create mode 100644 lib/virtio.c create mode 100644 lib/virtio.h diff --git a/lib/virtio-mmio.c b/lib/virtio-mmio.c new file mode 100644 index 0000000000000..7331abf128cc5 --- /dev/null +++ b/lib/virtio-mmio.c @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2014, Red Hat Inc, Andrew Jones + * + * This work is licensed under the terms of the GNU LGPL, version 2. + */ +#include "libcflat.h" +#include "devicetree.h" +#include "alloc.h" +#include "asm/io.h" +#include "virtio.h" +#include "virtio-mmio.h" + +static void vm_get(struct virtio_device *vdev, unsigned offset, + void *buf, unsigned len) +{ + struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); + u8 *p = buf; + unsigned i; + + for (i = 0; i < len; ++i) + p[i] = readb(vm_dev->base + VIRTIO_MMIO_CONFIG + offset + i); +} + +static void vm_set(struct virtio_device *vdev, unsigned offset, + const void *buf, unsigned len) +{ + struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); + const u8 *p = buf; + unsigned i; + + for (i = 0; i < len; ++i) + writeb(p[i], vm_dev->base + VIRTIO_MMIO_CONFIG + offset + i); +} + +static const struct virtio_config_ops vm_config_ops = { + .get = vm_get, + .set = vm_set, +}; + +static void vm_device_init(struct virtio_mmio_device *vm_dev) +{ + vm_dev->vdev.id.device = readl(vm_dev->base + VIRTIO_MMIO_DEVICE_ID); + vm_dev->vdev.id.vendor = readl(vm_dev->base + VIRTIO_MMIO_VENDOR_ID); + vm_dev->vdev.config = &vm_config_ops; +} + +/****************************************************** + * virtio-mmio device tree support + ******************************************************/ + +struct vm_dt_info { + u32 devid; + void *base; +}; + +static int vm_dt_match(const struct dt_device *dev, int fdtnode) +{ + struct vm_dt_info *info = (struct vm_dt_info *)dev->info; + struct dt_pbus_reg base; + u32 magic; + + dt_device_bind_node((struct dt_device *)dev, fdtnode); + + assert(dt_pbus_get_base(dev, &base) == 0); + info->base = ioremap(base.addr, base.size); + + magic = readl(info->base + VIRTIO_MMIO_MAGIC_VALUE); + if (magic != ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)) + return false; + + return readl(info->base + VIRTIO_MMIO_DEVICE_ID) == info->devid; +} + +static struct virtio_device *virtio_mmio_dt_bind(u32 devid) +{ + struct virtio_mmio_device *vm_dev; + struct dt_device dt_dev; + struct dt_bus dt_bus; + struct vm_dt_info info; + int node; + + if (!dt_available()) + return NULL; + + dt_bus_init_defaults(&dt_bus); + dt_bus.match = vm_dt_match; + + info.devid = devid; + + dt_device_init(&dt_dev, &dt_bus, &info); + + node = dt_device_find_compatible(&dt_dev, "virtio,mmio"); + assert(node >= 0 || node == -FDT_ERR_NOTFOUND); + + if (node == -FDT_ERR_NOTFOUND) + return NULL; + + vm_dev = calloc(1, sizeof(*vm_dev)); + if (!vm_dev) + return NULL; + + vm_dev->base = info.base; + vm_device_init(vm_dev); + + return &vm_dev->vdev; +} + +struct virtio_device *virtio_mmio_bind(u32 devid) +{ + return virtio_mmio_dt_bind(devid); +} diff --git a/lib/virtio-mmio.h b/lib/virtio-mmio.h new file mode 100644 index 0000000000000..7cd610428b486 --- /dev/null +++ b/lib/virtio-mmio.h @@ -0,0 +1,47 @@ +#ifndef _VIRTIO_MMIO_H_ +#define _VIRTIO_MMIO_H_ +/* + * A minimal implementation of virtio-mmio. Adapted from the Linux Kernel. + * + * Copyright (C) 2014, Red Hat Inc, Andrew Jones + * + * This work is licensed under the terms of the GNU LGPL, version 2. + */ +#include "libcflat.h" +#include "virtio.h" + +#define VIRTIO_MMIO_MAGIC_VALUE 0x000 +#define VIRTIO_MMIO_VERSION 0x004 +#define VIRTIO_MMIO_DEVICE_ID 0x008 +#define VIRTIO_MMIO_VENDOR_ID 0x00c +#define VIRTIO_MMIO_HOST_FEATURES 0x010 +#define VIRTIO_MMIO_HOST_FEATURES_SEL 0x014 +#define VIRTIO_MMIO_GUEST_FEATURES 0x020 +#define VIRTIO_MMIO_GUEST_FEATURES_SEL 0x024 +#define VIRTIO_MMIO_GUEST_PAGE_SIZE 0x028 +#define VIRTIO_MMIO_QUEUE_SEL 0x030 +#define VIRTIO_MMIO_QUEUE_NUM_MAX 0x034 +#define VIRTIO_MMIO_QUEUE_NUM 0x038 +#define VIRTIO_MMIO_QUEUE_ALIGN 0x03c +#define VIRTIO_MMIO_QUEUE_PFN 0x040 +#define VIRTIO_MMIO_QUEUE_NOTIFY 0x050 +#define VIRTIO_MMIO_INTERRUPT_STATUS 0x060 +#define VIRTIO_MMIO_INTERRUPT_ACK 0x064 +#define VIRTIO_MMIO_STATUS 0x070 +#define VIRTIO_MMIO_CONFIG 0x100 + +#define VIRTIO_MMIO_INT_VRING (1 << 0) +#define VIRTIO_MMIO_INT_CONFIG (1 << 1) + + +#define to_virtio_mmio_device(vdev_ptr) \ + container_of(vdev_ptr, struct virtio_mmio_device, vdev) + +struct virtio_mmio_device { + struct virtio_device vdev; + void *base; +}; + +extern struct virtio_device *virtio_mmio_bind(u32 devid); + +#endif /* _VIRTIO_MMIO_H_ */ diff --git a/lib/virtio.c b/lib/virtio.c new file mode 100644 index 0000000000000..b9c403cc71e05 --- /dev/null +++ b/lib/virtio.c @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2014, Red Hat Inc, Andrew Jones + * + * This work is licensed under the terms of the GNU LGPL, version 2. + */ +#include "libcflat.h" +#include "virtio.h" +#include "virtio-mmio.h" + +struct virtio_device *virtio_bind(u32 devid) +{ + return virtio_mmio_bind(devid); +} diff --git a/lib/virtio.h b/lib/virtio.h new file mode 100644 index 0000000000000..5941fa40a8655 --- /dev/null +++ b/lib/virtio.h @@ -0,0 +1,74 @@ +#ifndef _VIRTIO_H_ +#define _VIRTIO_H_ +/* + * A minimal implementation of virtio. + * Structures adapted from the Linux Kernel. + * + * Copyright (C) 2014, Red Hat Inc, Andrew Jones + * + * This work is licensed under the terms of the GNU LGPL, version 2. + */ +#include "libcflat.h" + +struct virtio_device_id { + u32 device; + u32 vendor; +}; + +struct virtio_device { + struct virtio_device_id id; + const struct virtio_config_ops *config; +}; + +struct virtio_config_ops { + void (*get)(struct virtio_device *vdev, unsigned offset, + void *buf, unsigned len); + void (*set)(struct virtio_device *vdev, unsigned offset, + const void *buf, unsigned len); +}; + +static inline u8 +virtio_config_readb(struct virtio_device *vdev, unsigned offset) +{ + u8 val; + vdev->config->get(vdev, offset, &val, 1); + return val; +} + +static inline u16 +virtio_config_readw(struct virtio_device *vdev, unsigned offset) +{ + u16 val; + vdev->config->get(vdev, offset, &val, 2); + return val; +} + +static inline u32 +virtio_config_readl(struct virtio_device *vdev, unsigned offset) +{ + u32 val; + vdev->config->get(vdev, offset, &val, 4); + return val; +} + +static inline void +virtio_config_writeb(struct virtio_device *vdev, unsigned offset, u8 val) +{ + vdev->config->set(vdev, offset, &val, 1); +} + +static inline void +virtio_config_writew(struct virtio_device *vdev, unsigned offset, u16 val) +{ + vdev->config->set(vdev, offset, &val, 2); +} + +static inline void +virtio_config_writel(struct virtio_device *vdev, unsigned offset, u32 val) +{ + vdev->config->set(vdev, offset, &val, 4); +} + +extern struct virtio_device *virtio_bind(u32 devid); + +#endif /* _VIRTIO_H_ */