Implement the NOTIFY_ON_EMPTY capability in the virtio-net device.

If this capability is negotiated by the guest then the device will
generate an interrupt when it runs out of available tx/rx descriptors.

Reviewed by:	grehan
Obtained from:	NetApp
This commit is contained in:
Neel Natu 2013-05-03 01:16:18 +00:00
parent 293e4eb67d
commit b1f3124565
2 changed files with 37 additions and 34 deletions

View File

@ -78,7 +78,8 @@ __FBSDID("$FreeBSD$");
#define VTNET_S_HOSTCAPS \ #define VTNET_S_HOSTCAPS \
( 0x00000020 | /* host supplies MAC */ \ ( 0x00000020 | /* host supplies MAC */ \
0x00008000 | /* host can merge Rx buffers */ \ 0x00008000 | /* host can merge Rx buffers */ \
0x00010000 ) /* config status available */ 0x00010000 | /* config status available */ \
VIRTIO_F_NOTIFY_ON_EMPTY)
/* /*
* Queue definitions. * Queue definitions.
@ -157,7 +158,8 @@ struct pci_vtnet_softc {
pthread_cond_t tx_cond; pthread_cond_t tx_cond;
int tx_in_progress; int tx_in_progress;
}; };
#define vtnet_ctx(sc) ((sc)->vsc_pi->pi_vmctx) #define vtnet_ctx(sc) ((sc)->vsc_pi->pi_vmctx)
#define notify_on_empty(sc) ((sc)->vsc_features & VIRTIO_F_NOTIFY_ON_EMPTY)
/* /*
* Return the size of IO BAR that maps virtio header and device specific * Return the size of IO BAR that maps virtio header and device specific
@ -289,6 +291,18 @@ pci_vtnet_update_status(struct pci_vtnet_softc *sc, uint32_t value)
sc->vsc_status = value; sc->vsc_status = value;
} }
static void
vtnet_generate_interrupt(struct pci_vtnet_softc *sc, int qidx)
{
if (use_msix) {
pci_generate_msix(sc->vsc_pi, sc->vsc_msix_table_idx[qidx]);
} else {
sc->vsc_isr |= 1;
pci_generate_msi(sc->vsc_pi, 0);
}
}
/* /*
* Called to send a buffer chain out to the tap device * Called to send a buffer chain out to the tap device
*/ */
@ -366,6 +380,10 @@ pci_vtnet_tap_rx(struct pci_vtnet_softc *sc)
* Drop the packet and try later * Drop the packet and try later
*/ */
(void) read(sc->vsc_tapfd, dummybuf, sizeof(dummybuf)); (void) read(sc->vsc_tapfd, dummybuf, sizeof(dummybuf));
if (notify_on_empty(sc))
vtnet_generate_interrupt(sc, VTNET_RXQ);
return; return;
} }
@ -418,15 +436,8 @@ pci_vtnet_tap_rx(struct pci_vtnet_softc *sc)
*hq->hq_used_idx = uidx; *hq->hq_used_idx = uidx;
hq->hq_cur_aidx = aidx; hq->hq_cur_aidx = aidx;
if ((*hq->hq_avail_flags & VRING_AVAIL_F_NO_INTERRUPT) == 0) { if ((*hq->hq_avail_flags & VRING_AVAIL_F_NO_INTERRUPT) == 0)
if (use_msix) { vtnet_generate_interrupt(sc, VTNET_RXQ);
pci_generate_msix(sc->vsc_pi,
sc->vsc_msix_table_idx[VTNET_RXQ]);
} else {
sc->vsc_isr |= 1;
pci_generate_msi(sc->vsc_pi, 0);
}
}
} }
static void static void
@ -536,9 +547,8 @@ pci_vtnet_tx_thread(void *param)
{ {
struct pci_vtnet_softc *sc = (struct pci_vtnet_softc *) param; struct pci_vtnet_softc *sc = (struct pci_vtnet_softc *) param;
struct vring_hqueue *hq; struct vring_hqueue *hq;
int i, ndescs, needintr,error; int i, ndescs, error;
needintr = 0;
hq = &sc->vsc_hq[VTNET_TXQ]; hq = &sc->vsc_hq[VTNET_TXQ];
/* /*
@ -552,31 +562,14 @@ pci_vtnet_tx_thread(void *param)
for (;;) { for (;;) {
pthread_mutex_lock(&sc->tx_mtx); pthread_mutex_lock(&sc->tx_mtx);
for (;;) { for (;;) {
if (sc->resetting) { if (sc->resetting)
ndescs = 0; ndescs = 0;
needintr = 0; else
} else
ndescs = hq_num_avail(hq); ndescs = hq_num_avail(hq);
if (ndescs != 0) if (ndescs != 0)
break; break;
if (needintr) {
/*
* Generate an interrupt if able
*/
if ((*hq->hq_avail_flags &
VRING_AVAIL_F_NO_INTERRUPT) == 0) {
if (use_msix) {
pci_generate_msix(sc->vsc_pi,
sc->vsc_msix_table_idx[VTNET_TXQ]);
} else {
sc->vsc_isr |= 1;
pci_generate_msi(sc->vsc_pi, 0);
}
}
}
needintr = 0;
sc->tx_in_progress = 0; sc->tx_in_progress = 0;
error = pthread_cond_wait(&sc->tx_cond, &sc->tx_mtx); error = pthread_cond_wait(&sc->tx_cond, &sc->tx_mtx);
assert(error == 0); assert(error == 0);
@ -591,9 +584,16 @@ pci_vtnet_tx_thread(void *param)
*/ */
for (i = 0; i < ndescs; i++) for (i = 0; i < ndescs; i++)
pci_vtnet_proctx(sc, hq); pci_vtnet_proctx(sc, hq);
needintr = 1;
ndescs = hq_num_avail(hq); ndescs = hq_num_avail(hq);
} }
/*
* Generate an interrupt if needed.
*/
if (notify_on_empty(sc) ||
(*hq->hq_avail_flags & VRING_AVAIL_F_NO_INTERRUPT) == 0)
vtnet_generate_interrupt(sc, VTNET_TXQ);
} }
} }

View File

@ -85,6 +85,9 @@ struct virtio_used {
#define VTCFG_R_CFG1 24 /* With MSI-X */ #define VTCFG_R_CFG1 24 /* With MSI-X */
#define VTCFG_R_MSIX 20 #define VTCFG_R_MSIX 20
/* Feature flags */
#define VIRTIO_F_NOTIFY_ON_EMPTY (1 << 24)
/* From section 2.3, "Virtqueue Configuration", of the virtio specification */ /* From section 2.3, "Virtqueue Configuration", of the virtio specification */
static inline u_int static inline u_int
vring_size(u_int qsz) vring_size(u_int qsz)