Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
Show First 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | |||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/queue.h> | #include <sys/queue.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/sx.h> | #include <sys/sx.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/buf_ring.h> | |||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <net/if_arp.h> | #include <net/if_arp.h> | ||||
#include <net/ethernet.h> | #include <net/ethernet.h> | ||||
#include <net/if_dl.h> | #include <net/if_dl.h> | ||||
#include <net/if_media.h> | #include <net/if_media.h> | ||||
#include <net/bpf.h> | #include <net/bpf.h> | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | |||||
#define HN_TX_DATA_MAXSIZE IP_MAXPACKET | #define HN_TX_DATA_MAXSIZE IP_MAXPACKET | ||||
#define HN_TX_DATA_SEGSIZE PAGE_SIZE | #define HN_TX_DATA_SEGSIZE PAGE_SIZE | ||||
#define HN_TX_DATA_SEGCNT_MAX \ | #define HN_TX_DATA_SEGCNT_MAX \ | ||||
(NETVSC_PACKET_MAXPAGE - HV_RF_NUM_TX_RESERVED_PAGE_BUFS) | (NETVSC_PACKET_MAXPAGE - HV_RF_NUM_TX_RESERVED_PAGE_BUFS) | ||||
#define HN_DIRECT_TX_SIZE_DEF 128 | #define HN_DIRECT_TX_SIZE_DEF 128 | ||||
struct hn_txdesc { | struct hn_txdesc { | ||||
#ifndef HN_USE_TXDESC_BUFRING | |||||
SLIST_ENTRY(hn_txdesc) link; | SLIST_ENTRY(hn_txdesc) link; | ||||
#endif | |||||
struct mbuf *m; | struct mbuf *m; | ||||
struct hn_tx_ring *txr; | struct hn_tx_ring *txr; | ||||
int refs; | int refs; | ||||
uint32_t flags; /* HN_TXD_FLAG_ */ | uint32_t flags; /* HN_TXD_FLAG_ */ | ||||
netvsc_packet netvsc_pkt; /* XXX to be removed */ | netvsc_packet netvsc_pkt; /* XXX to be removed */ | ||||
bus_dmamap_t data_dmap; | bus_dmamap_t data_dmap; | ||||
▲ Show 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
static int hn_share_tx_taskq = 0; | static int hn_share_tx_taskq = 0; | ||||
SYSCTL_INT(_hw_hn, OID_AUTO, share_tx_taskq, CTLFLAG_RDTUN, | SYSCTL_INT(_hw_hn, OID_AUTO, share_tx_taskq, CTLFLAG_RDTUN, | ||||
&hn_share_tx_taskq, 0, "Enable shared TX taskqueue"); | &hn_share_tx_taskq, 0, "Enable shared TX taskqueue"); | ||||
static struct taskqueue *hn_tx_taskq; | static struct taskqueue *hn_tx_taskq; | ||||
#ifndef HN_USE_TXDESC_BUFRING | |||||
static int hn_use_txdesc_bufring = 0; | |||||
#else | |||||
static int hn_use_txdesc_bufring = 1; | |||||
#endif | |||||
SYSCTL_INT(_hw_hn, OID_AUTO, use_txdesc_bufring, CTLFLAG_RD, | |||||
&hn_use_txdesc_bufring, 0, "Use buf_ring for TX descriptors"); | |||||
/* | /* | ||||
* Forward declarations | * Forward declarations | ||||
*/ | */ | ||||
static void hn_stop(hn_softc_t *sc); | static void hn_stop(hn_softc_t *sc); | ||||
static void hn_ifinit_locked(hn_softc_t *sc); | static void hn_ifinit_locked(hn_softc_t *sc); | ||||
static void hn_ifinit(void *xsc); | static void hn_ifinit(void *xsc); | ||||
static int hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); | static int hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); | ||||
static int hn_start_locked(struct hn_tx_ring *txr, int len); | static int hn_start_locked(struct hn_tx_ring *txr, int len); | ||||
▲ Show 20 Lines • Show All 296 Lines • ▼ Show 20 Lines | hn_txdesc_put(struct hn_tx_ring *txr, struct hn_txdesc *txd) | ||||
hn_txdesc_dmamap_unload(txr, txd); | hn_txdesc_dmamap_unload(txr, txd); | ||||
if (txd->m != NULL) { | if (txd->m != NULL) { | ||||
m_freem(txd->m); | m_freem(txd->m); | ||||
txd->m = NULL; | txd->m = NULL; | ||||
} | } | ||||
txd->flags |= HN_TXD_FLAG_ONLIST; | txd->flags |= HN_TXD_FLAG_ONLIST; | ||||
#ifndef HN_USE_TXDESC_BUFRING | |||||
mtx_lock_spin(&txr->hn_txlist_spin); | mtx_lock_spin(&txr->hn_txlist_spin); | ||||
KASSERT(txr->hn_txdesc_avail >= 0 && | KASSERT(txr->hn_txdesc_avail >= 0 && | ||||
txr->hn_txdesc_avail < txr->hn_txdesc_cnt, | txr->hn_txdesc_avail < txr->hn_txdesc_cnt, | ||||
("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail)); | ("txdesc_put: invalid txd avail %d", txr->hn_txdesc_avail)); | ||||
txr->hn_txdesc_avail++; | txr->hn_txdesc_avail++; | ||||
SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link); | SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link); | ||||
mtx_unlock_spin(&txr->hn_txlist_spin); | mtx_unlock_spin(&txr->hn_txlist_spin); | ||||
#else | |||||
atomic_add_int(&txr->hn_txdesc_avail, 1); | |||||
buf_ring_enqueue(txr->hn_txdesc_br, txd); | |||||
#endif | |||||
return 1; | return 1; | ||||
} | } | ||||
static __inline struct hn_txdesc * | static __inline struct hn_txdesc * | ||||
hn_txdesc_get(struct hn_tx_ring *txr) | hn_txdesc_get(struct hn_tx_ring *txr) | ||||
{ | { | ||||
struct hn_txdesc *txd; | struct hn_txdesc *txd; | ||||
#ifndef HN_USE_TXDESC_BUFRING | |||||
mtx_lock_spin(&txr->hn_txlist_spin); | mtx_lock_spin(&txr->hn_txlist_spin); | ||||
txd = SLIST_FIRST(&txr->hn_txlist); | txd = SLIST_FIRST(&txr->hn_txlist); | ||||
if (txd != NULL) { | if (txd != NULL) { | ||||
KASSERT(txr->hn_txdesc_avail > 0, | KASSERT(txr->hn_txdesc_avail > 0, | ||||
("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail)); | ("txdesc_get: invalid txd avail %d", txr->hn_txdesc_avail)); | ||||
txr->hn_txdesc_avail--; | txr->hn_txdesc_avail--; | ||||
SLIST_REMOVE_HEAD(&txr->hn_txlist, link); | SLIST_REMOVE_HEAD(&txr->hn_txlist, link); | ||||
} | } | ||||
mtx_unlock_spin(&txr->hn_txlist_spin); | mtx_unlock_spin(&txr->hn_txlist_spin); | ||||
#else | |||||
txd = buf_ring_dequeue_sc(txr->hn_txdesc_br); | |||||
#endif | |||||
if (txd != NULL) { | if (txd != NULL) { | ||||
#ifdef HN_USE_TXDESC_BUFRING | |||||
atomic_subtract_int(&txr->hn_txdesc_avail, 1); | |||||
#endif | |||||
KASSERT(txd->m == NULL && txd->refs == 0 && | KASSERT(txd->m == NULL && txd->refs == 0 && | ||||
(txd->flags & HN_TXD_FLAG_ONLIST), ("invalid txd")); | (txd->flags & HN_TXD_FLAG_ONLIST), ("invalid txd")); | ||||
txd->flags &= ~HN_TXD_FLAG_ONLIST; | txd->flags &= ~HN_TXD_FLAG_ONLIST; | ||||
txd->refs = 1; | txd->refs = 1; | ||||
} | } | ||||
return txd; | return txd; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,435 Lines • ▼ Show 20 Lines | |||||
hn_create_tx_ring(struct hn_softc *sc, int id) | hn_create_tx_ring(struct hn_softc *sc, int id) | ||||
{ | { | ||||
struct hn_tx_ring *txr = &sc->hn_tx_ring[id]; | struct hn_tx_ring *txr = &sc->hn_tx_ring[id]; | ||||
bus_dma_tag_t parent_dtag; | bus_dma_tag_t parent_dtag; | ||||
int error, i; | int error, i; | ||||
txr->hn_sc = sc; | txr->hn_sc = sc; | ||||
#ifndef HN_USE_TXDESC_BUFRING | |||||
mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN); | mtx_init(&txr->hn_txlist_spin, "hn txlist", NULL, MTX_SPIN); | ||||
#endif | |||||
mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF); | mtx_init(&txr->hn_tx_lock, "hn tx", NULL, MTX_DEF); | ||||
txr->hn_txdesc_cnt = HN_TX_DESC_CNT; | txr->hn_txdesc_cnt = HN_TX_DESC_CNT; | ||||
txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt, | txr->hn_txdesc = malloc(sizeof(struct hn_txdesc) * txr->hn_txdesc_cnt, | ||||
M_NETVSC, M_WAITOK | M_ZERO); | M_NETVSC, M_WAITOK | M_ZERO); | ||||
#ifndef HN_USE_TXDESC_BUFRING | |||||
SLIST_INIT(&txr->hn_txlist); | SLIST_INIT(&txr->hn_txlist); | ||||
#else | |||||
txr->hn_txdesc_br = buf_ring_alloc(txr->hn_txdesc_cnt, M_NETVSC, | |||||
M_WAITOK, &txr->hn_tx_lock); | |||||
#endif | |||||
txr->hn_tx_taskq = sc->hn_tx_taskq; | txr->hn_tx_taskq = sc->hn_tx_taskq; | ||||
TASK_INIT(&txr->hn_start_task, 0, hn_start_taskfunc, txr); | TASK_INIT(&txr->hn_start_task, 0, hn_start_taskfunc, txr); | ||||
TASK_INIT(&txr->hn_txeof_task, 0, hn_txeof_taskfunc, txr); | TASK_INIT(&txr->hn_txeof_task, 0, hn_txeof_taskfunc, txr); | ||||
txr->hn_direct_tx_size = hn_direct_tx_size; | txr->hn_direct_tx_size = hn_direct_tx_size; | ||||
if (hv_vmbus_protocal_version >= HV_VMBUS_VERSION_WIN8_1) | if (hv_vmbus_protocal_version >= HV_VMBUS_VERSION_WIN8_1) | ||||
txr->hn_csum_assist = HN_CSUM_ASSIST; | txr->hn_csum_assist = HN_CSUM_ASSIST; | ||||
▲ Show 20 Lines • Show All 87 Lines • ▼ Show 20 Lines | if (error) { | ||||
txd->rndis_msg_dmap); | txd->rndis_msg_dmap); | ||||
bus_dmamem_free(txr->hn_tx_rndis_dtag, | bus_dmamem_free(txr->hn_tx_rndis_dtag, | ||||
txd->rndis_msg, txd->rndis_msg_dmap); | txd->rndis_msg, txd->rndis_msg_dmap); | ||||
return error; | return error; | ||||
} | } | ||||
/* All set, put it to list */ | /* All set, put it to list */ | ||||
txd->flags |= HN_TXD_FLAG_ONLIST; | txd->flags |= HN_TXD_FLAG_ONLIST; | ||||
#ifndef HN_USE_TXDESC_BUFRING | |||||
SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link); | SLIST_INSERT_HEAD(&txr->hn_txlist, txd, link); | ||||
#else | |||||
buf_ring_enqueue(txr->hn_txdesc_br, txd); | |||||
#endif | |||||
} | } | ||||
txr->hn_txdesc_avail = txr->hn_txdesc_cnt; | txr->hn_txdesc_avail = txr->hn_txdesc_cnt; | ||||
if (sc->hn_tx_sysctl_tree != NULL) { | if (sc->hn_tx_sysctl_tree != NULL) { | ||||
struct sysctl_oid_list *child; | struct sysctl_oid_list *child; | ||||
struct sysctl_ctx_list *ctx; | struct sysctl_ctx_list *ctx; | ||||
char name[16]; | char name[16]; | ||||
Show All 16 Lines | if (txr->hn_tx_sysctl_tree != NULL) { | ||||
"# of available TX descs"); | "# of available TX descs"); | ||||
} | } | ||||
} | } | ||||
return 0; | return 0; | ||||
} | } | ||||
static void | static void | ||||
hn_txdesc_dmamap_destroy(struct hn_txdesc *txd) | |||||
{ | |||||
struct hn_tx_ring *txr = txd->txr; | |||||
KASSERT(txd->m == NULL, ("still has mbuf installed")); | |||||
KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, ("still dma mapped")); | |||||
bus_dmamap_unload(txr->hn_tx_rndis_dtag, txd->rndis_msg_dmap); | |||||
bus_dmamem_free(txr->hn_tx_rndis_dtag, txd->rndis_msg, | |||||
txd->rndis_msg_dmap); | |||||
bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap); | |||||
} | |||||
static void | |||||
hn_destroy_tx_ring(struct hn_tx_ring *txr) | hn_destroy_tx_ring(struct hn_tx_ring *txr) | ||||
{ | { | ||||
struct hn_txdesc *txd; | struct hn_txdesc *txd; | ||||
if (txr->hn_txdesc == NULL) | if (txr->hn_txdesc == NULL) | ||||
return; | return; | ||||
#ifndef HN_USE_TXDESC_BUFRING | |||||
while ((txd = SLIST_FIRST(&txr->hn_txlist)) != NULL) { | while ((txd = SLIST_FIRST(&txr->hn_txlist)) != NULL) { | ||||
KASSERT(txd->m == NULL, ("still has mbuf installed")); | |||||
KASSERT((txd->flags & HN_TXD_FLAG_DMAMAP) == 0, | |||||
("still dma mapped")); | |||||
SLIST_REMOVE_HEAD(&txr->hn_txlist, link); | SLIST_REMOVE_HEAD(&txr->hn_txlist, link); | ||||
hn_txdesc_dmamap_destroy(txd); | |||||
bus_dmamap_unload(txr->hn_tx_rndis_dtag, | |||||
txd->rndis_msg_dmap); | |||||
bus_dmamem_free(txr->hn_tx_rndis_dtag, | |||||
txd->rndis_msg, txd->rndis_msg_dmap); | |||||
bus_dmamap_destroy(txr->hn_tx_data_dtag, txd->data_dmap); | |||||
} | } | ||||
#else | |||||
while ((txd = buf_ring_dequeue_sc(txr->hn_txdesc_br)) != NULL) | |||||
hn_txdesc_dmamap_destroy(txd); | |||||
#endif | |||||
if (txr->hn_tx_data_dtag != NULL) | if (txr->hn_tx_data_dtag != NULL) | ||||
bus_dma_tag_destroy(txr->hn_tx_data_dtag); | bus_dma_tag_destroy(txr->hn_tx_data_dtag); | ||||
if (txr->hn_tx_rndis_dtag != NULL) | if (txr->hn_tx_rndis_dtag != NULL) | ||||
bus_dma_tag_destroy(txr->hn_tx_rndis_dtag); | bus_dma_tag_destroy(txr->hn_tx_rndis_dtag); | ||||
free(txr->hn_txdesc, M_NETVSC); | free(txr->hn_txdesc, M_NETVSC); | ||||
txr->hn_txdesc = NULL; | txr->hn_txdesc = NULL; | ||||
#ifndef HN_USE_TXDESC_BUFRING | |||||
mtx_destroy(&txr->hn_txlist_spin); | mtx_destroy(&txr->hn_txlist_spin); | ||||
#endif | |||||
mtx_destroy(&txr->hn_tx_lock); | mtx_destroy(&txr->hn_tx_lock); | ||||
} | } | ||||
static int | static int | ||||
hn_create_tx_data(struct hn_softc *sc) | hn_create_tx_data(struct hn_softc *sc) | ||||
{ | { | ||||
struct sysctl_oid_list *child; | struct sysctl_oid_list *child; | ||||
struct sysctl_ctx_list *ctx; | struct sysctl_ctx_list *ctx; | ||||
▲ Show 20 Lines • Show All 170 Lines • Show Last 20 Lines |