<commit_before>/*-
 * Copyright (c) 2011 NetApp, Inc.
 * 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 NETAPP, INC ``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 NETAPP, INC 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.
 *
 * $FreeBSD$
 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");

#include <sys/param.h>
#include <sys/linker_set.h>
#include <sys/select.h>
#include <sys/uio.h>
#include <sys/ioctl.h>

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <assert.h>
#include <md5.h>
#include <pthread.h>

#include "fbsdrun.h"
#include "pci_emul.h"
#include "mevent.h"
#include "virtio.h"

#define VTNET_RINGSZ	256

#define VTNET_MAXSEGS	32

/*
 * PCI config-space register offsets
 */
#define VTNET_R_CFG0	       20
#define VTNET_R_CFG1	       21
#define VTNET_R_CFG2	       22
#define VTNET_R_CFG3	       23
#define VTNET_R_CFG4	       24
#define VTNET_R_CFG5	       25
#define VTNET_R_CFG6	       26
#define VTNET_R_CFG7	       27
#define VTNET_R_MAX	       27

#define VTNET_REGSZ		VTNET_R_MAX+1

/*
 * Host capabilities
 */
#define VTNET_S_HOSTCAPS      \
  ( 0x00000020 |	/* host supplies MAC */ \
    0x00008000 |	/* host can merge Rx buffers */ \
    0x00010000 )	/* config status available */

/*
 * Queue definitions.
 */
#define VTNET_RXQ	0
#define VTNET_TXQ	1
#define VTNET_CTLQ	2

#define VTNET_MAXQ	3

struct vring_hqueue {
	/* Internal state */
	uint16_t	hq_size;
	uint16_t	hq_cur_aidx;		/* trails behind 'avail_idx' */

	 /* Host-context pointers to the queue */
	struct virtio_desc *hq_dtable;
	uint16_t	*hq_avail_flags;
	uint16_t	*hq_avail_idx;		/* monotonically increasing */
	uint16_t	*hq_avail_ring;

	uint16_t	*hq_used_flags;
	uint16_t	*hq_used_idx;		/* monotonically increasing */
	struct virtio_used *hq_used_ring;
};

/*
 * Fixed network header size
 */
struct virtio_net_rxhdr {
	uint8_t		vrh_flags;
	uint8_t		vrh_gso_type;
	uint16_t	vrh_hdr_len;
	uint16_t	vrh_gso_size;
	uint16_t	vrh_csum_start;
	uint16_t	vrh_csum_offset;
	uint16_t	vrh_bufs;
} __packed;

/*
 * Debug printf
 */
static int pci_vtnet_debug;
#define DPRINTF(params) if (pci_vtnet_debug) printf params
#define WPRINTF(params) printf params

/*
 * Per-device softc
 */
struct pci_vtnet_softc {
	struct pci_devinst *vsc_pi;
	pthread_mutex_t vsc_mtx;
	struct mevent	*vsc_mevp;

	int		vsc_curq;
	int		vsc_status;
	int		vsc_isr;
	int		vsc_tapfd;
	int		vsc_rx_ready;
	int		vsc_rxpend;

	uint32_t	vsc_features;
	uint8_t		vsc_macaddr[6];

	uint64_t	vsc_pfn[VTNET_MAXQ];
	struct	vring_hqueue vsc_hq[VTNET_MAXQ];
};

/*
 * Return the number of available descriptors in the vring taking care
 * of the 16-bit index wraparound.
 */
static int
hq_num_avail(struct vring_hqueue *hq)
{
	int ndesc;

	if (*hq->hq_avail_idx >= hq->hq_cur_aidx)
		ndesc = *hq->hq_avail_idx - hq->hq_cur_aidx;
	else
		ndesc = UINT16_MAX - hq->hq_cur_aidx + *hq->hq_avail_idx + 1;

	assert(ndesc >= 0 && ndesc <= hq->hq_size);

	return (ndesc);
}

static uint16_t
pci_vtnet_qsize(int qnum)
{
	/* XXX no ctl queue currently */
	if (qnum == VTNET_CTLQ) {
		return (0);
	}

	/* XXX fixed currently. Maybe different for tx/rx/ctl */
	return (VTNET_RINGSZ);
}

static void
pci_vtnet_update_status(struct pci_vtnet_softc *sc, uint32_t value)
{
	if (value == 0) {
		DPRINTF(("vtnet: device reset requested !\n"));
	}

	sc->vsc_status = value;
}

/*
 * Called to send a buffer chain out to the tap device
 */<commit_msg>Properly reset the tx/rx rings when a guest requests a device reset.<commit_after>/*-
 * Copyright (c) 2011 NetApp, Inc.
 * 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 NETAPP, INC ``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 NETAPP, INC 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.
 *
 * $FreeBSD$
 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");

#include <sys/param.h>
#include <sys/linker_set.h>
#include <sys/select.h>
#include <sys/uio.h>
#include <sys/ioctl.h>

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <assert.h>
#include <md5.h>
#include <pthread.h>

#include "fbsdrun.h"
#include "pci_emul.h"
#include "mevent.h"
#include "virtio.h"

#define VTNET_RINGSZ	256

#define VTNET_MAXSEGS	32

/*
 * PCI config-space register offsets
 */
#define VTNET_R_CFG0	       20
#define VTNET_R_CFG1	       21
#define VTNET_R_CFG2	       22
#define VTNET_R_CFG3	       23
#define VTNET_R_CFG4	       24
#define VTNET_R_CFG5	       25
#define VTNET_R_CFG6	       26
#define VTNET_R_CFG7	       27
#define VTNET_R_MAX	       27

#define VTNET_REGSZ		VTNET_R_MAX+1

/*
 * Host capabilities
 */
#define VTNET_S_HOSTCAPS      \
  ( 0x00000020 |	/* host supplies MAC */ \
    0x00008000 |	/* host can merge Rx buffers */ \
    0x00010000 )	/* config status available */

/*
 * Queue definitions.
 */
#define VTNET_RXQ	0
#define VTNET_TXQ	1
#define VTNET_CTLQ	2

#define VTNET_MAXQ	3

struct vring_hqueue {
	/* Internal state */
	uint16_t	hq_size;
	uint16_t	hq_cur_aidx;		/* trails behind 'avail_idx' */

	 /* Host-context pointers to the queue */
	struct virtio_desc *hq_dtable;
	uint16_t	*hq_avail_flags;
	uint16_t	*hq_avail_idx;		/* monotonically increasing */
	uint16_t	*hq_avail_ring;

	uint16_t	*hq_used_flags;
	uint16_t	*hq_used_idx;		/* monotonically increasing */
	struct virtio_used *hq_used_ring;
};

/*
 * Fixed network header size
 */
struct virtio_net_rxhdr {
	uint8_t		vrh_flags;
	uint8_t		vrh_gso_type;
	uint16_t	vrh_hdr_len;
	uint16_t	vrh_gso_size;
	uint16_t	vrh_csum_start;
	uint16_t	vrh_csum_offset;
	uint16_t	vrh_bufs;
} __packed;

/*
 * Debug printf
 */
static int pci_vtnet_debug;
#define DPRINTF(params) if (pci_vtnet_debug) printf params
#define WPRINTF(params) printf params

/*
 * Per-device softc
 */
struct pci_vtnet_softc {
	struct pci_devinst *vsc_pi;
	pthread_mutex_t vsc_mtx;
	struct mevent	*vsc_mevp;

	int		vsc_curq;
	int		vsc_status;
	int		vsc_isr;
	int		vsc_tapfd;
	int		vsc_rx_ready;
	int		vsc_rxpend;

	uint32_t	vsc_features;
	uint8_t		vsc_macaddr[6];

	uint64_t	vsc_pfn[VTNET_MAXQ];
	struct	vring_hqueue vsc_hq[VTNET_MAXQ];
};

/*
 * Return the number of available descriptors in the vring taking care
 * of the 16-bit index wraparound.
 */
static int
hq_num_avail(struct vring_hqueue *hq)
{
	int ndesc;

	if (*hq->hq_avail_idx >= hq->hq_cur_aidx)
		ndesc = *hq->hq_avail_idx - hq->hq_cur_aidx;
	else
		ndesc = UINT16_MAX - hq->hq_cur_aidx + *hq->hq_avail_idx + 1;

	assert(ndesc >= 0 && ndesc <= hq->hq_size);

	return (ndesc);
}

static uint16_t
pci_vtnet_qsize(int qnum)
{
	/* XXX no ctl queue currently */
	if (qnum == VTNET_CTLQ) {
		return (0);
	}

	/* XXX fixed currently. Maybe different for tx/rx/ctl */
	return (VTNET_RINGSZ);
}

static void
pci_vtnet_ring_reset(struct pci_vtnet_softc *sc, int ring)
{
	struct vring_hqueue *hq;

	assert(ring < VTNET_MAXQ);

	hq = &sc->vsc_hq[ring];

	/*
	 * Reset all soft state
	 */
	hq->hq_cur_aidx = 0;
}

static void
pci_vtnet_update_status(struct pci_vtnet_softc *sc, uint32_t value)
{

	if (value == 0) {
		DPRINTF(("vtnet: device reset requested !\n"));
		pci_vtnet_ring_reset(sc, VTNET_RXQ);
		pci_vtnet_ring_reset(sc, VTNET_TXQ);
		sc->vsc_rx_ready = 0;
	}

	sc->vsc_status = value;
}

/*
 * Called to send a buffer chain out to the tap device
 */
{'fraction_non_alphanumeric': 0.09706311185169757, 'fraction_numerical': 0.023953343053530515, 'mean_word_length': 3.95, 'pattern_counts': {'":': 0, '<': 40, '<?xml version=': 0, '>': 60, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6252135', 'n_tokens_mistral': 3930, 'n_tokens_neox': 3671, 'n_words': 1043}