Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
Show First 20 Lines • Show All 170 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Only enable UDP checksum offloading when it is on 2012R2 or | * Only enable UDP checksum offloading when it is on 2012R2 or | ||||
* later. UDP checksum offloading doesn't work on earlier | * later. UDP checksum offloading doesn't work on earlier | ||||
* Windows releases. | * Windows releases. | ||||
*/ | */ | ||||
#define HN_CSUM_ASSIST_WIN8 (CSUM_TCP) | #define HN_CSUM_ASSIST_WIN8 (CSUM_TCP) | ||||
#define HN_CSUM_ASSIST (CSUM_IP | CSUM_UDP | CSUM_TCP) | #define HN_CSUM_ASSIST (CSUM_IP | CSUM_UDP | CSUM_TCP) | ||||
/* XXX move to netinet/tcp_lro.h */ | #define HN_LRO_ACK_APPEND_LIM 1 | ||||
#define HN_LRO_HIWAT_MAX 65535 | #define HN_LRO_DATA_APPEND_LIM 25 | ||||
#define HN_LRO_HIWAT_DEF HN_LRO_HIWAT_MAX | |||||
/* YYY 2*MTU is a bit rough, but should be good enough. */ | |||||
#define HN_LRO_HIWAT_MTULIM(ifp) (2 * (ifp)->if_mtu) | |||||
#define HN_LRO_HIWAT_ISVALID(sc, hiwat) \ | |||||
((hiwat) >= HN_LRO_HIWAT_MTULIM((sc)->hn_ifp) || \ | |||||
(hiwat) <= HN_LRO_HIWAT_MAX) | |||||
/* | /* | ||||
* Be aware that this sleepable mutex will exhibit WITNESS errors when | * Be aware that this sleepable mutex will exhibit WITNESS errors when | ||||
* certain TCP and ARP code paths are taken. This appears to be a | * certain TCP and ARP code paths are taken. This appears to be a | ||||
* well-known condition, as all other drivers checked use a sleeping | * well-known condition, as all other drivers checked use a sleeping | ||||
* mutex to protect their transmit paths. | * mutex to protect their transmit paths. | ||||
* Also Be aware that mutexes do not play well with semaphores, and there | * Also Be aware that mutexes do not play well with semaphores, and there | ||||
* is a conflicting semaphore in a certain channel code path. | * is a conflicting semaphore in a certain channel code path. | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | |||||
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 ifnet *ifp, int len); | static int hn_start_locked(struct ifnet *ifp, int len); | ||||
static void hn_start(struct ifnet *ifp); | static void hn_start(struct ifnet *ifp); | ||||
static void hn_start_txeof(struct ifnet *ifp); | static void hn_start_txeof(struct ifnet *ifp); | ||||
static int hn_ifmedia_upd(struct ifnet *ifp); | static int hn_ifmedia_upd(struct ifnet *ifp); | ||||
static void hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr); | static void hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr); | ||||
#ifdef HN_LRO_HIWAT | |||||
static int hn_lro_hiwat_sysctl(SYSCTL_HANDLER_ARGS); | |||||
#endif | |||||
static int hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS); | static int hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS); | ||||
static int hn_tx_chimney_size_sysctl(SYSCTL_HANDLER_ARGS); | static int hn_tx_chimney_size_sysctl(SYSCTL_HANDLER_ARGS); | ||||
static int hn_lro_append_lim_sysctl(SYSCTL_HANDLER_ARGS); | |||||
static int hn_check_iplen(const struct mbuf *, int); | static int hn_check_iplen(const struct mbuf *, int); | ||||
static int hn_create_tx_ring(struct hn_softc *sc); | static int hn_create_tx_ring(struct hn_softc *sc); | ||||
static void hn_destroy_tx_ring(struct hn_softc *sc); | static void hn_destroy_tx_ring(struct hn_softc *sc); | ||||
static void hn_start_taskfunc(void *xsc, int pending); | static void hn_start_taskfunc(void *xsc, int pending); | ||||
static void hn_txeof_taskfunc(void *xsc, int pending); | static void hn_txeof_taskfunc(void *xsc, int pending); | ||||
static int hn_encap(struct hn_softc *, struct hn_txdesc *, struct mbuf **); | static int hn_encap(struct hn_softc *, struct hn_txdesc *, struct mbuf **); | ||||
static __inline void | |||||
hn_set_lro_hiwat(struct hn_softc *sc, int hiwat) | |||||
{ | |||||
sc->hn_lro_hiwat = hiwat; | |||||
#ifdef HN_LRO_HIWAT | |||||
sc->hn_lro.lro_hiwat = sc->hn_lro_hiwat; | |||||
#endif | |||||
} | |||||
static int | static int | ||||
hn_ifmedia_upd(struct ifnet *ifp __unused) | hn_ifmedia_upd(struct ifnet *ifp __unused) | ||||
{ | { | ||||
return EOPNOTSUPP; | return EOPNOTSUPP; | ||||
} | } | ||||
static void | static void | ||||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | #endif | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
if (sc == NULL) { | if (sc == NULL) { | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
bzero(sc, sizeof(hn_softc_t)); | bzero(sc, sizeof(hn_softc_t)); | ||||
sc->hn_unit = unit; | sc->hn_unit = unit; | ||||
sc->hn_dev = dev; | sc->hn_dev = dev; | ||||
sc->hn_lro_hiwat = HN_LRO_HIWAT_DEF; | |||||
sc->hn_direct_tx_size = hn_direct_tx_size; | sc->hn_direct_tx_size = hn_direct_tx_size; | ||||
if (hn_trust_hosttcp) | if (hn_trust_hosttcp) | ||||
sc->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP; | sc->hn_trust_hcsum |= HN_TRUST_HCSUM_TCP; | ||||
if (hn_trust_hostudp) | if (hn_trust_hostudp) | ||||
sc->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP; | sc->hn_trust_hcsum |= HN_TRUST_HCSUM_UDP; | ||||
if (hn_trust_hostip) | if (hn_trust_hostip) | ||||
sc->hn_trust_hcsum |= HN_TRUST_HCSUM_IP; | sc->hn_trust_hcsum |= HN_TRUST_HCSUM_IP; | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | if (lroent_cnt < TCP_LRO_ENTRIES) | ||||
lroent_cnt = TCP_LRO_ENTRIES; | lroent_cnt = TCP_LRO_ENTRIES; | ||||
tcp_lro_init_args(&sc->hn_lro, ifp, lroent_cnt, 0); | tcp_lro_init_args(&sc->hn_lro, ifp, lroent_cnt, 0); | ||||
device_printf(dev, "LRO: entry count %d\n", lroent_cnt); | device_printf(dev, "LRO: entry count %d\n", lroent_cnt); | ||||
#else | #else | ||||
tcp_lro_init(&sc->hn_lro); | tcp_lro_init(&sc->hn_lro); | ||||
/* Driver private LRO settings */ | /* Driver private LRO settings */ | ||||
sc->hn_lro.ifp = ifp; | sc->hn_lro.ifp = ifp; | ||||
#endif | #endif | ||||
#ifdef HN_LRO_HIWAT | sc->hn_lro.lro_ack_append_lim = HN_LRO_ACK_APPEND_LIM; | ||||
sc->hn_lro.lro_hiwat = sc->hn_lro_hiwat; | sc->hn_lro.lro_data_append_lim = HN_LRO_DATA_APPEND_LIM; | ||||
#endif | |||||
#endif /* INET || INET6 */ | #endif /* INET || INET6 */ | ||||
#if __FreeBSD_version >= 1100045 | #if __FreeBSD_version >= 1100045 | ||||
tso_maxlen = hn_tso_maxlen; | tso_maxlen = hn_tso_maxlen; | ||||
if (tso_maxlen <= 0 || tso_maxlen > IP_MAXPACKET) | if (tso_maxlen <= 0 || tso_maxlen > IP_MAXPACKET) | ||||
tso_maxlen = IP_MAXPACKET; | tso_maxlen = IP_MAXPACKET; | ||||
ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX; | ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX; | ||||
Show All 10 Lines | |||||
#endif | #endif | ||||
sc->hn_tx_chimney_max = sc->net_dev->send_section_size; | sc->hn_tx_chimney_max = sc->net_dev->send_section_size; | ||||
sc->hn_tx_chimney_size = sc->hn_tx_chimney_max; | sc->hn_tx_chimney_size = sc->hn_tx_chimney_max; | ||||
if (hn_tx_chimney_size > 0 && | if (hn_tx_chimney_size > 0 && | ||||
hn_tx_chimney_size < sc->hn_tx_chimney_max) | hn_tx_chimney_size < sc->hn_tx_chimney_max) | ||||
sc->hn_tx_chimney_size = hn_tx_chimney_size; | sc->hn_tx_chimney_size = hn_tx_chimney_size; | ||||
/* | |||||
adrian: this should be a separate commit | |||||
sepherosa_gmail.comAuthorUnsubmitted Not Done Inline ActionsOK, I will split it out. sepherosa_gmail.com: OK, I will split it out. | |||||
* Always schedule transmission instead of trying | |||||
* to do direct transmission. This one gives the | |||||
* best performance so far. | |||||
*/ | |||||
sc->hn_sched_tx = 1; | |||||
ctx = device_get_sysctl_ctx(dev); | ctx = device_get_sysctl_ctx(dev); | ||||
child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); | child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); | ||||
SYSCTL_ADD_U64(ctx, child, OID_AUTO, "lro_queued", | SYSCTL_ADD_U64(ctx, child, OID_AUTO, "lro_queued", | ||||
CTLFLAG_RW, &sc->hn_lro.lro_queued, 0, "LRO queued"); | CTLFLAG_RW, &sc->hn_lro.lro_queued, 0, "LRO queued"); | ||||
SYSCTL_ADD_U64(ctx, child, OID_AUTO, "lro_flushed", | SYSCTL_ADD_U64(ctx, child, OID_AUTO, "lro_flushed", | ||||
CTLFLAG_RW, &sc->hn_lro.lro_flushed, 0, "LRO flushed"); | CTLFLAG_RW, &sc->hn_lro.lro_flushed, 0, "LRO flushed"); | ||||
SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "lro_tried", | SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "lro_tried", | ||||
CTLFLAG_RW, &sc->hn_lro_tried, "# of LRO tries"); | CTLFLAG_RW, &sc->hn_lro_tried, "# of LRO tries"); | ||||
#ifdef HN_LRO_HIWAT | |||||
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_hiwat", | |||||
CTLTYPE_INT | CTLFLAG_RW, sc, 0, hn_lro_hiwat_sysctl, | |||||
"I", "LRO high watermark"); | |||||
#endif | |||||
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp", | SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hosttcp", | ||||
CTLTYPE_INT | CTLFLAG_RW, sc, HN_TRUST_HCSUM_TCP, | CTLTYPE_INT | CTLFLAG_RW, sc, HN_TRUST_HCSUM_TCP, | ||||
hn_trust_hcsum_sysctl, "I", | hn_trust_hcsum_sysctl, "I", | ||||
"Trust tcp segement verification on host side, " | "Trust tcp segement verification on host side, " | ||||
"when csum info is missing"); | "when csum info is missing"); | ||||
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp", | SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "trust_hostudp", | ||||
CTLTYPE_INT | CTLFLAG_RW, sc, HN_TRUST_HCSUM_UDP, | CTLTYPE_INT | CTLFLAG_RW, sc, HN_TRUST_HCSUM_UDP, | ||||
hn_trust_hcsum_sysctl, "I", | hn_trust_hcsum_sysctl, "I", | ||||
Show All 37 Lines | SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "tx_chimney_size", | ||||
"I", "Chimney send packet size limit"); | "I", "Chimney send packet size limit"); | ||||
SYSCTL_ADD_INT(ctx, child, OID_AUTO, "direct_tx_size", | SYSCTL_ADD_INT(ctx, child, OID_AUTO, "direct_tx_size", | ||||
CTLFLAG_RW, &sc->hn_direct_tx_size, 0, | CTLFLAG_RW, &sc->hn_direct_tx_size, 0, | ||||
"Size of the packet for direct transmission"); | "Size of the packet for direct transmission"); | ||||
SYSCTL_ADD_INT(ctx, child, OID_AUTO, "sched_tx", | SYSCTL_ADD_INT(ctx, child, OID_AUTO, "sched_tx", | ||||
CTLFLAG_RW, &sc->hn_sched_tx, 0, | CTLFLAG_RW, &sc->hn_sched_tx, 0, | ||||
"Always schedule transmission " | "Always schedule transmission " | ||||
"instead of doing direct transmission"); | "instead of doing direct transmission"); | ||||
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_ack_append_lim", | |||||
CTLTYPE_INT | CTLFLAG_RW, &sc->hn_lro.lro_ack_append_lim, | |||||
0, hn_lro_append_lim_sysctl, | |||||
"I", "LRO ACK appending limitation"); | |||||
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "lro_data_append_lim", | |||||
CTLTYPE_INT | CTLFLAG_RW, &sc->hn_lro.lro_data_append_lim, | |||||
0, hn_lro_append_lim_sysctl, | |||||
"I", "LRO data segments appending limitation"); | |||||
if (unit == 0) { | if (unit == 0) { | ||||
struct sysctl_ctx_list *dc_ctx; | struct sysctl_ctx_list *dc_ctx; | ||||
struct sysctl_oid_list *dc_child; | struct sysctl_oid_list *dc_child; | ||||
devclass_t dc; | devclass_t dc; | ||||
/* | /* | ||||
* Add sysctl nodes for devclass | * Add sysctl nodes for devclass | ||||
▲ Show 20 Lines • Show All 856 Lines • ▼ Show 20 Lines | case SIOCSIFMTU: | ||||
if (ifr->ifr_mtu > NETVSC_MAX_CONFIGURABLE_MTU) { | if (ifr->ifr_mtu > NETVSC_MAX_CONFIGURABLE_MTU) { | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
/* Obtain and record requested MTU */ | /* Obtain and record requested MTU */ | ||||
ifp->if_mtu = ifr->ifr_mtu; | ifp->if_mtu = ifr->ifr_mtu; | ||||
/* | |||||
* Make sure that LRO high watermark is still valid, | |||||
* after MTU change (the 2*MTU limit). | |||||
*/ | |||||
if (!HN_LRO_HIWAT_ISVALID(sc, sc->hn_lro_hiwat)) | |||||
hn_set_lro_hiwat(sc, HN_LRO_HIWAT_MTULIM(ifp)); | |||||
do { | do { | ||||
NV_LOCK(sc); | NV_LOCK(sc); | ||||
if (!sc->temp_unusable) { | if (!sc->temp_unusable) { | ||||
sc->temp_unusable = TRUE; | sc->temp_unusable = TRUE; | ||||
retry_cnt = -1; | retry_cnt = -1; | ||||
} | } | ||||
NV_UNLOCK(sc); | NV_UNLOCK(sc); | ||||
if (retry_cnt > 0) { | if (retry_cnt > 0) { | ||||
▲ Show 20 Lines • Show All 289 Lines • ▼ Show 20 Lines | hn_watchdog(struct ifnet *ifp) | ||||
sc = ifp->if_softc; | sc = ifp->if_softc; | ||||
printf("hn%d: watchdog timeout -- resetting\n", sc->hn_unit); | printf("hn%d: watchdog timeout -- resetting\n", sc->hn_unit); | ||||
hn_ifinit(sc); /*???*/ | hn_ifinit(sc); /*???*/ | ||||
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); | ||||
} | } | ||||
#endif | #endif | ||||
#ifdef HN_LRO_HIWAT | |||||
static int | static int | ||||
hn_lro_hiwat_sysctl(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
struct hn_softc *sc = arg1; | |||||
int hiwat, error; | |||||
hiwat = sc->hn_lro_hiwat; | |||||
error = sysctl_handle_int(oidp, &hiwat, 0, req); | |||||
if (error || req->newptr == NULL) | |||||
return error; | |||||
if (!HN_LRO_HIWAT_ISVALID(sc, hiwat)) | |||||
return EINVAL; | |||||
if (sc->hn_lro_hiwat != hiwat) | |||||
hn_set_lro_hiwat(sc, hiwat); | |||||
return 0; | |||||
} | |||||
#endif /* HN_LRO_HIWAT */ | |||||
static int | |||||
hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS) | hn_trust_hcsum_sysctl(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct hn_softc *sc = arg1; | struct hn_softc *sc = arg1; | ||||
int hcsum = arg2; | int hcsum = arg2; | ||||
int on, error; | int on, error; | ||||
on = 0; | on = 0; | ||||
if (sc->hn_trust_hcsum & hcsum) | if (sc->hn_trust_hcsum & hcsum) | ||||
Show All 23 Lines | hn_tx_chimney_size_sysctl(SYSCTL_HANDLER_ARGS) | ||||
if (error || req->newptr == NULL) | if (error || req->newptr == NULL) | ||||
return error; | return error; | ||||
if (chimney_size > sc->hn_tx_chimney_max || chimney_size <= 0) | if (chimney_size > sc->hn_tx_chimney_max || chimney_size <= 0) | ||||
return EINVAL; | return EINVAL; | ||||
if (sc->hn_tx_chimney_size != chimney_size) | if (sc->hn_tx_chimney_size != chimney_size) | ||||
sc->hn_tx_chimney_size = chimney_size; | sc->hn_tx_chimney_size = chimney_size; | ||||
return 0; | |||||
} | |||||
static int | |||||
hn_lro_append_lim_sysctl(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
unsigned short *lro_lim = arg1; | |||||
int lim, error; | |||||
lim = *lro_lim; | |||||
error = sysctl_handle_int(oidp, &lim, 0, req); | |||||
if (error || req->newptr == NULL) | |||||
return error; | |||||
if (lim < 0 || lim > 65535) | |||||
return EINVAL; | |||||
*lro_lim = lim; | |||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
hn_check_iplen(const struct mbuf *m, int hoff) | hn_check_iplen(const struct mbuf *m, int hoff) | ||||
{ | { | ||||
const struct ip *ip; | const struct ip *ip; | ||||
int len, iphlen, iplen; | int len, iphlen, iplen; | ||||
▲ Show 20 Lines • Show All 257 Lines • Show Last 20 Lines |
this should be a separate commit