Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 5 Aug 2016 13:53:35 GMT
From:      vincenzo@FreeBSD.org
To:        svn-soc-all@FreeBSD.org
Subject:   socsvn commit: r307218 - soc2016/vincenzo/head/usr.sbin/bhyve
Message-ID:  <201608051353.u75DrZQF036169@socsvn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: vincenzo
Date: Fri Aug  5 13:53:35 2016
New Revision: 307218
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=307218

Log:
  add support for ptnetmap PCI device

Added:
  soc2016/vincenzo/head/usr.sbin/bhyve/pci_ptnetmap_memdev.c
Modified:
  soc2016/vincenzo/head/usr.sbin/bhyve/Makefile

Modified: soc2016/vincenzo/head/usr.sbin/bhyve/Makefile
==============================================================================
--- soc2016/vincenzo/head/usr.sbin/bhyve/Makefile	Fri Aug  5 13:51:56 2016	(r307217)
+++ soc2016/vincenzo/head/usr.sbin/bhyve/Makefile	Fri Aug  5 13:53:35 2016	(r307218)
@@ -32,6 +32,7 @@
 	pci_irq.c		\
 	pci_lpc.c		\
 	pci_passthru.c		\
+	pci_ptnetmap_memdev.c	\
 	pci_virtio_block.c	\
 	pci_virtio_net.c	\
 	pci_virtio_rnd.c	\

Added: soc2016/vincenzo/head/usr.sbin/bhyve/pci_ptnetmap_memdev.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ soc2016/vincenzo/head/usr.sbin/bhyve/pci_ptnetmap_memdev.c	Fri Aug  5 13:53:35 2016	(r307218)
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2015 Stefano Garzarella (stefano.garzarella@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <net/if.h>	/* IFNAMSIZ */
+#include <net/netmap.h>
+#include <dev/netmap/netmap_virt.h>
+
+#include <machine/vmm.h>
+#include <vmmapi.h>
+
+#include "bhyverun.h"
+#include "pci_emul.h"
+
+/*
+ * ptnetmap memdev PCI device
+ *
+ * This device is used to map a netmap memory allocator on the guest VM
+ * through PCI_BAR. The same allocator can be shared between multiple ptnetmap
+ * ports in the guest.
+ *
+ * Each netmap allocator has a unique ID assigned by the netmap host module.
+ *
+ * The implementation here is based on the QEMU/KVM one.
+ */
+struct ptn_memdev_softc {
+	struct pci_devinst *pi;		/* PCI device instance */
+
+	void *mem_ptr;			/* netmap shared memory */
+	uint64_t mem_size;		/* netmap shared memory size */
+	uint16_t mem_id;		/* netmap memory allocator ID */
+
+	TAILQ_ENTRY(ptn_memdev_softc) next;
+};
+static TAILQ_HEAD(, ptn_memdev_softc) ptn_memdevs = TAILQ_HEAD_INITIALIZER(ptn_memdevs);
+
+/*
+ * ptn_memdev_softc can be created by pe_init or ptnetmap backend,
+ * this depends on the order of initialization.
+ */
+static struct ptn_memdev_softc *
+ptn_memdev_create()
+{
+	struct ptn_memdev_softc *sc;
+
+	sc = calloc(1, sizeof(struct ptn_memdev_softc));
+	if (sc != NULL) {
+		TAILQ_INSERT_TAIL(&ptn_memdevs, sc, next);
+	}
+
+	return sc;
+}
+
+static void
+ptn_memdev_delete(struct ptn_memdev_softc *sc)
+{
+	TAILQ_REMOVE(&ptn_memdevs, sc, next);
+
+	free(sc);
+}
+
+/*
+ * Find ptn_memdev through mem_id (netmap memory allocator ID)
+ */
+static struct ptn_memdev_softc *
+ptn_memdev_find_memid(uint16_t mem_id)
+{
+	struct ptn_memdev_softc *sc;
+
+	TAILQ_FOREACH(sc, &ptn_memdevs, next) {
+		if (sc->mem_ptr != NULL && mem_id == sc->mem_id) {
+			return sc;
+		}
+	}
+
+	return NULL;
+}
+
+/*
+ * Find ptn_memdev that has not netmap memory (attached by ptnetmap backend)
+ */
+static struct ptn_memdev_softc *
+ptn_memdev_find_empty_mem()
+{
+	struct ptn_memdev_softc *sc;
+
+	TAILQ_FOREACH(sc, &ptn_memdevs, next) {
+		if (sc->mem_ptr == NULL) {
+			return sc;
+		}
+	}
+
+	return NULL;
+}
+
+/*
+ * Find ptn_memdev that has not PCI device istance (created by pe_init)
+ */
+static struct ptn_memdev_softc *
+ptn_memdev_find_empty_pi()
+{
+	struct ptn_memdev_softc *sc;
+
+	TAILQ_FOREACH(sc, &ptn_memdevs, next) {
+		if (sc->pi == NULL) {
+			return sc;
+		}
+	}
+
+	return NULL;
+}
+
+/*
+ * Handle read on ptnetmap-memdev register
+ */
+static uint64_t
+ptn_pci_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
+	     int baridx, uint64_t offset, int size)
+{
+	struct ptn_memdev_softc *sc = pi->pi_arg;
+
+	if (sc == NULL)
+		return 0;
+
+	if (baridx == PTNETMAP_IO_PCI_BAR) {
+		switch (offset) {
+			case PTNETMAP_IO_PCI_MEMSIZE:
+				return sc->mem_size;
+			case PTNETMAP_IO_PCI_HOSTID:
+				return sc->mem_id;
+		}
+	}
+
+	printf("%s: Unexpected register read [bar %u, offset %lx size %d]\n",
+		__func__, baridx, offset, size);
+
+	return 0;
+}
+
+/*
+ * Handle write on ptnetmap-memdev register (unused for now)
+ */
+static void
+ptn_pci_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
+	      int baridx, uint64_t offset, int size, uint64_t value)
+{
+	struct ptn_memdev_softc *sc = pi->pi_arg;
+
+	if (sc == NULL)
+		return;
+
+	printf("%s: Unexpected register write [bar %u, offset %lx size %d "
+	       "value %lx]\n", __func__, baridx, offset, size, value);
+}
+
+/*
+ * Configure the ptnetmap-memdev PCI BARs. PCI BARs can only be created
+ * when the PCI device is created and the netmap memory is attached.
+ */
+static int
+ptn_memdev_configure_bars(struct ptn_memdev_softc *sc)
+{
+	int ret;
+
+	if (sc->pi == NULL || sc->mem_ptr == NULL)
+		return 0;
+
+	/* Allocate a BAR for an I/O region. */
+	ret = pci_emul_alloc_bar(sc->pi, PTNETMAP_IO_PCI_BAR, PCIBAR_IO,
+				 PTNETMAP_IO_SIZE);
+	if (ret) {
+		printf("ptnetmap_memdev: iobar allocation error %d\n", ret);
+		return ret;
+	}
+
+	/* Allocate a BAR for a memory region. */
+	ret = pci_emul_alloc_bar(sc->pi, PTNETMAP_MEM_PCI_BAR, PCIBAR_MEM32,
+			sc->mem_size);
+	if (ret) {
+		printf("ptnetmap_memdev: membar allocation error %d\n", ret);
+		return ret;
+	}
+
+	/* Map netmap memory on the memory BAR. */
+	ret = vm_map_user_buf(sc->pi->pi_vmctx,
+			      sc->pi->pi_bar[PTNETMAP_MEM_PCI_BAR].addr,
+			      sc->mem_size, sc->mem_ptr);
+	if (ret) {
+		printf("ptnetmap_memdev: membar map error %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * PCI device initialization
+ */
+static int
+ptn_memdev_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
+{
+	struct ptn_memdev_softc *sc;
+	int ret;
+
+	sc = ptn_memdev_find_empty_pi();
+	if (sc == NULL) {
+		sc = ptn_memdev_create();
+		if (sc == NULL) {
+			printf("ptnetmap_memdev: calloc error\n");
+			return (ENOMEM);
+		}
+	}
+
+	/* Link our softc in the pci_devinst. */
+	pi->pi_arg = sc;
+	sc->pi = pi;
+
+	/* Initialize PCI configuration space. */
+	pci_set_cfgdata16(pi, PCIR_VENDOR, PTNETMAP_PCI_VENDOR_ID);
+	pci_set_cfgdata16(pi, PCIR_DEVICE, PTNETMAP_PCI_DEVICE_ID);
+	pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_NETWORK);
+	pci_set_cfgdata16(pi, PCIR_SUBDEV_0, 1);
+	pci_set_cfgdata16(pi, PCIR_SUBVEND_0, PTNETMAP_PCI_VENDOR_ID);
+
+	/* Configure PCI-BARs. */
+	ret = ptn_memdev_configure_bars(sc);
+	if (ret) {
+		printf("ptnetmap_memdev: configure error\n");
+		goto err;
+	}
+
+	return 0;
+err:
+	ptn_memdev_delete(sc);
+	pi->pi_arg = NULL;
+	return ret;
+}
+
+/*
+ * used by ptnetmap backend to attach the netmap memory allocator to the
+ * ptnetmap-memdev. (shared with the guest VM through PCI-BAR)
+ */
+int
+ptn_memdev_attach(void *mem_ptr, uint32_t mem_size, uint16_t mem_id)
+{
+	struct ptn_memdev_softc *sc;
+	int ret;
+
+	/* if a device with the same mem_id is already attached, we are done */
+	if (ptn_memdev_find_memid(mem_id)) {
+		printf("ptnetmap_memdev: already attched\n");
+		return 0;
+	}
+
+	sc = ptn_memdev_find_empty_mem();
+	if (sc == NULL) {
+		sc = ptn_memdev_create();
+		if (sc == NULL) {
+			printf("ptnetmap_memdev: calloc error\n");
+			return (ENOMEM);
+		}
+	}
+
+	sc->mem_ptr = mem_ptr;
+	sc->mem_size = mem_size;
+	sc->mem_id = mem_id;
+
+	/* configure device PCI-BARs */
+	ret = ptn_memdev_configure_bars(sc);
+	if (ret) {
+		printf("ptnetmap_memdev: configure error\n");
+		goto err;
+	}
+
+
+	return 0;
+err:
+	ptn_memdev_delete(sc);
+	sc->pi->pi_arg = NULL;
+	return ret;
+}
+
+struct pci_devemu pci_de_ptnetmap = {
+	.pe_emu = 	PTN_MEMDEV_NAME,
+	.pe_init =	ptn_memdev_init,
+	.pe_barwrite =	ptn_pci_write,
+	.pe_barread =	ptn_pci_read
+};
+PCI_EMUL_SET(pci_de_ptnetmap);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201608051353.u75DrZQF036169>