Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/hyperv/netvsc/if_hn.c
Show First 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | |||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/limits.h> | #include <sys/limits.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/mbuf.h> | #include <sys/mbuf.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/queue.h> | #include <sys/queue.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/rmlock.h> | |||||
#include <sys/sbuf.h> | |||||
#include <sys/smp.h> | #include <sys/smp.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/sockio.h> | #include <sys/sockio.h> | ||||
#include <sys/sx.h> | #include <sys/sx.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/taskqueue.h> | #include <sys/taskqueue.h> | ||||
#include <sys/buf_ring.h> | #include <sys/buf_ring.h> | ||||
Show All 34 Lines | |||||
#include <dev/hyperv/netvsc/hn_rndis.h> | #include <dev/hyperv/netvsc/hn_rndis.h> | ||||
#include "vmbus_if.h" | #include "vmbus_if.h" | ||||
#define HN_IFSTART_SUPPORT | #define HN_IFSTART_SUPPORT | ||||
#define HN_RING_CNT_DEF_MAX 8 | #define HN_RING_CNT_DEF_MAX 8 | ||||
#define HN_VFMAP_SIZE_DEF 8 | |||||
/* YYY should get it from the underlying channel */ | /* YYY should get it from the underlying channel */ | ||||
#define HN_TX_DESC_CNT 512 | #define HN_TX_DESC_CNT 512 | ||||
#define HN_RNDIS_PKT_LEN \ | #define HN_RNDIS_PKT_LEN \ | ||||
(sizeof(struct rndis_packet_msg) + \ | (sizeof(struct rndis_packet_msg) + \ | ||||
HN_RNDIS_PKTINFO_SIZE(HN_NDIS_HASH_VALUE_SIZE) + \ | HN_RNDIS_PKTINFO_SIZE(HN_NDIS_HASH_VALUE_SIZE) + \ | ||||
HN_RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) + \ | HN_RNDIS_PKTINFO_SIZE(NDIS_VLAN_INFO_SIZE) + \ | ||||
HN_RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) + \ | HN_RNDIS_PKTINFO_SIZE(NDIS_LSO2_INFO_SIZE) + \ | ||||
▲ Show 20 Lines • Show All 120 Lines • ▼ Show 20 Lines | |||||
static void hn_start(struct ifnet *); | static void hn_start(struct ifnet *); | ||||
#endif | #endif | ||||
static int hn_transmit(struct ifnet *, struct mbuf *); | static int hn_transmit(struct ifnet *, struct mbuf *); | ||||
static void hn_xmit_qflush(struct ifnet *); | static void hn_xmit_qflush(struct ifnet *); | ||||
static int hn_ifmedia_upd(struct ifnet *); | static int hn_ifmedia_upd(struct ifnet *); | ||||
static void hn_ifmedia_sts(struct ifnet *, | static void hn_ifmedia_sts(struct ifnet *, | ||||
struct ifmediareq *); | struct ifmediareq *); | ||||
static void hn_ifnet_event(void *, struct ifnet *, int); | |||||
static void hn_ifaddr_event(void *, struct ifnet *); | |||||
static void hn_ifnet_attevent(void *, struct ifnet *); | |||||
static void hn_ifnet_detevent(void *, struct ifnet *); | |||||
static int hn_rndis_rxinfo(const void *, int, | static int hn_rndis_rxinfo(const void *, int, | ||||
struct hn_rxinfo *); | struct hn_rxinfo *); | ||||
static void hn_rndis_rx_data(struct hn_rx_ring *, | static void hn_rndis_rx_data(struct hn_rx_ring *, | ||||
const void *, int); | const void *, int); | ||||
static void hn_rndis_rx_status(struct hn_softc *, | static void hn_rndis_rx_status(struct hn_softc *, | ||||
const void *, int); | const void *, int); | ||||
static void hn_rndis_init_fixat(struct hn_softc *, int); | static void hn_rndis_init_fixat(struct hn_softc *, int); | ||||
Show All 32 Lines | |||||
#endif | #endif | ||||
static int hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS); | static int hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS); | ||||
static int hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS); | static int hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS); | ||||
static int hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS); | static int hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS); | ||||
static int hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS); | static int hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS); | ||||
static int hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS); | static int hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS); | ||||
static int hn_polling_sysctl(SYSCTL_HANDLER_ARGS); | static int hn_polling_sysctl(SYSCTL_HANDLER_ARGS); | ||||
static int hn_vf_sysctl(SYSCTL_HANDLER_ARGS); | static int hn_vf_sysctl(SYSCTL_HANDLER_ARGS); | ||||
static int hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS); | |||||
static int hn_vflist_sysctl(SYSCTL_HANDLER_ARGS); | |||||
static int hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS); | |||||
static void hn_stop(struct hn_softc *, bool); | static void hn_stop(struct hn_softc *, bool); | ||||
static void hn_init_locked(struct hn_softc *); | static void hn_init_locked(struct hn_softc *); | ||||
static int hn_chan_attach(struct hn_softc *, | static int hn_chan_attach(struct hn_softc *, | ||||
struct vmbus_channel *); | struct vmbus_channel *); | ||||
static void hn_chan_detach(struct hn_softc *, | static void hn_chan_detach(struct hn_softc *, | ||||
struct vmbus_channel *); | struct vmbus_channel *); | ||||
static int hn_attach_subchans(struct hn_softc *); | static int hn_attach_subchans(struct hn_softc *); | ||||
▲ Show 20 Lines • Show All 183 Lines • ▼ Show 20 Lines | |||||
SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_size, CTLFLAG_RDTUN, | SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_size, CTLFLAG_RDTUN, | ||||
&hn_tx_agg_size, 0, "Packet transmission aggregation size limit"); | &hn_tx_agg_size, 0, "Packet transmission aggregation size limit"); | ||||
/* Packet transmission aggregation count limit */ | /* Packet transmission aggregation count limit */ | ||||
static int hn_tx_agg_pkts = -1; | static int hn_tx_agg_pkts = -1; | ||||
SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN, | SYSCTL_INT(_hw_hn, OID_AUTO, tx_agg_pkts, CTLFLAG_RDTUN, | ||||
&hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit"); | &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit"); | ||||
/* VF list */ | |||||
SYSCTL_PROC(_hw_hn, OID_AUTO, vflist, CTLFLAG_RD | CTLTYPE_STRING, | |||||
0, 0, hn_vflist_sysctl, "A", "VF list"); | |||||
/* VF mapping */ | |||||
SYSCTL_PROC(_hw_hn, OID_AUTO, vfmap, CTLFLAG_RD | CTLTYPE_STRING, | |||||
0, 0, hn_vfmap_sysctl, "A", "VF mapping"); | |||||
static u_int hn_cpu_index; /* next CPU for channel */ | static u_int hn_cpu_index; /* next CPU for channel */ | ||||
static struct taskqueue **hn_tx_taskque;/* shared TX taskqueues */ | static struct taskqueue **hn_tx_taskque;/* shared TX taskqueues */ | ||||
static struct rmlock hn_vfmap_lock; | |||||
static int hn_vfmap_size; | |||||
static struct ifnet **hn_vfmap; | |||||
#ifndef RSS | #ifndef RSS | ||||
static const uint8_t | static const uint8_t | ||||
hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = { | hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = { | ||||
0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2, | 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2, | ||||
0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0, | 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0, | ||||
0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4, | 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4, | ||||
0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c, | 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c, | ||||
0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa | 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa | ||||
▲ Show 20 Lines • Show All 450 Lines • ▼ Show 20 Lines | hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) | ||||
ifmr->ifm_active |= IFM_10G_T | IFM_FDX; | ifmr->ifm_active |= IFM_10G_T | IFM_FDX; | ||||
} | } | ||||
static void | static void | ||||
hn_update_vf_task(void *arg, int pending __unused) | hn_update_vf_task(void *arg, int pending __unused) | ||||
{ | { | ||||
struct hn_update_vf *uv = arg; | struct hn_update_vf *uv = arg; | ||||
uv->rxr->hn_vf = uv->vf; | uv->rxr->hn_rxvf_ifp = uv->vf; | ||||
} | } | ||||
static void | static void | ||||
hn_update_vf(struct hn_softc *sc, struct ifnet *vf) | hn_update_vf(struct hn_softc *sc, struct ifnet *vf) | ||||
{ | { | ||||
struct hn_rx_ring *rxr; | struct hn_rx_ring *rxr; | ||||
struct hn_update_vf uv; | struct hn_update_vf uv; | ||||
struct task task; | struct task task; | ||||
int i; | int i; | ||||
HN_LOCK_ASSERT(sc); | HN_LOCK_ASSERT(sc); | ||||
TASK_INIT(&task, 0, hn_update_vf_task, &uv); | TASK_INIT(&task, 0, hn_update_vf_task, &uv); | ||||
for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { | for (i = 0; i < sc->hn_rx_ring_cnt; ++i) { | ||||
rxr = &sc->hn_rx_ring[i]; | rxr = &sc->hn_rx_ring[i]; | ||||
if (i < sc->hn_rx_ring_inuse) { | if (i < sc->hn_rx_ring_inuse) { | ||||
uv.rxr = rxr; | uv.rxr = rxr; | ||||
uv.vf = vf; | uv.vf = vf; | ||||
vmbus_chan_run_task(rxr->hn_chan, &task); | vmbus_chan_run_task(rxr->hn_chan, &task); | ||||
} else { | } else { | ||||
rxr->hn_vf = vf; | rxr->hn_rxvf_ifp = vf; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
static void | static __inline bool | ||||
hn_set_vf(struct hn_softc *sc, struct ifnet *ifp, bool vf) | hn_ismyvf(const struct hn_softc *sc, const struct ifnet *ifp) | ||||
{ | { | ||||
struct ifnet *hn_ifp; | const struct ifnet *hn_ifp; | ||||
HN_LOCK(sc); | |||||
if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)) | |||||
goto out; | |||||
hn_ifp = sc->hn_ifp; | hn_ifp = sc->hn_ifp; | ||||
if (ifp == hn_ifp) | if (ifp == hn_ifp) | ||||
goto out; | return (false); | ||||
if (ifp->if_alloctype != IFT_ETHER) | if (ifp->if_alloctype != IFT_ETHER) | ||||
goto out; | return (false); | ||||
/* Ignore lagg/vlan interfaces */ | /* Ignore lagg/vlan interfaces */ | ||||
if (strcmp(ifp->if_dname, "lagg") == 0 || | if (strcmp(ifp->if_dname, "lagg") == 0 || | ||||
strcmp(ifp->if_dname, "vlan") == 0) | strcmp(ifp->if_dname, "vlan") == 0) | ||||
goto out; | return (false); | ||||
if (bcmp(IF_LLADDR(ifp), IF_LLADDR(hn_ifp), ETHER_ADDR_LEN) != 0) | if (bcmp(IF_LLADDR(ifp), IF_LLADDR(hn_ifp), ETHER_ADDR_LEN) != 0) | ||||
return (false); | |||||
return (true); | |||||
} | |||||
static void | |||||
hn_set_vf(struct hn_softc *sc, struct ifnet *ifp, bool vf) | |||||
{ | |||||
struct ifnet *hn_ifp; | |||||
HN_LOCK(sc); | |||||
if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)) | |||||
goto out; | goto out; | ||||
if (!hn_ismyvf(sc, ifp)) | |||||
goto out; | |||||
hn_ifp = sc->hn_ifp; | |||||
/* Now we're sure 'ifp' is a real VF device. */ | /* Now we're sure 'ifp' is a real VF device. */ | ||||
if (vf) { | if (vf) { | ||||
if (sc->hn_flags & HN_FLAG_VF) | if (sc->hn_flags & HN_FLAG_VF) | ||||
goto out; | goto out; | ||||
sc->hn_flags |= HN_FLAG_VF; | sc->hn_flags |= HN_FLAG_VF; | ||||
hn_rxfilter_config(sc); | hn_rxfilter_config(sc); | ||||
} else { | } else { | ||||
if (!(sc->hn_flags & HN_FLAG_VF)) | if (!(sc->hn_flags & HN_FLAG_VF)) | ||||
goto out; | goto out; | ||||
sc->hn_flags &= ~HN_FLAG_VF; | sc->hn_flags &= ~HN_FLAG_VF; | ||||
if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) | if (hn_ifp->if_drv_flags & IFF_DRV_RUNNING) | ||||
hn_rxfilter_config(sc); | hn_rxfilter_config(sc); | ||||
else | else | ||||
hn_set_rxfilter(sc, NDIS_PACKET_TYPE_NONE); | hn_set_rxfilter(sc, NDIS_PACKET_TYPE_NONE); | ||||
} | } | ||||
hn_nvs_set_datapath(sc, | hn_nvs_set_datapath(sc, | ||||
vf ? HN_NVS_DATAPATH_VF : HN_NVS_DATAPATH_SYNTHETIC); | vf ? HN_NVS_DATAPATH_VF : HN_NVS_DATAPATH_SYNTHETIC); | ||||
hn_update_vf(sc, vf ? ifp : NULL); | hn_update_vf(sc, vf ? ifp : NULL); | ||||
if (vf) { | if (vf) { | ||||
hn_suspend_mgmt(sc); | hn_suspend_mgmt(sc); | ||||
sc->hn_link_flags &= | sc->hn_link_flags &= | ||||
~(HN_LINK_FLAG_LINKUP | HN_LINK_FLAG_NETCHG); | ~(HN_LINK_FLAG_LINKUP | HN_LINK_FLAG_NETCHG); | ||||
if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN); | if_link_state_change(hn_ifp, LINK_STATE_DOWN); | ||||
} else { | } else { | ||||
hn_resume_mgmt(sc); | hn_resume_mgmt(sc); | ||||
} | } | ||||
devctl_notify("HYPERV_NIC_VF", if_name(hn_ifp), | devctl_notify("HYPERV_NIC_VF", if_name(hn_ifp), | ||||
vf ? "VF_UP" : "VF_DOWN", NULL); | vf ? "VF_UP" : "VF_DOWN", NULL); | ||||
if (bootverbose) | if (bootverbose) | ||||
Show All 13 Lines | |||||
} | } | ||||
static void | static void | ||||
hn_ifaddr_event(void *arg, struct ifnet *ifp) | hn_ifaddr_event(void *arg, struct ifnet *ifp) | ||||
{ | { | ||||
hn_set_vf(arg, ifp, ifp->if_flags & IFF_UP); | hn_set_vf(arg, ifp, ifp->if_flags & IFF_UP); | ||||
} | } | ||||
static void | |||||
hn_ifnet_attevent(void *xsc, struct ifnet *ifp) | |||||
{ | |||||
struct hn_softc *sc = xsc; | |||||
HN_LOCK(sc); | |||||
if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)) | |||||
goto done; | |||||
if (!hn_ismyvf(sc, ifp)) | |||||
goto done; | |||||
if (sc->hn_vf_ifp != NULL) { | |||||
if_printf(sc->hn_ifp, "%s was attached as VF\n", | |||||
sc->hn_vf_ifp->if_xname); | |||||
goto done; | |||||
} | |||||
rm_wlock(&hn_vfmap_lock); | |||||
if (ifp->if_index >= hn_vfmap_size) { | |||||
struct ifnet **newmap; | |||||
int newsize; | |||||
newsize = ifp->if_index + HN_VFMAP_SIZE_DEF; | |||||
newmap = malloc(sizeof(struct ifnet *) * newsize, M_DEVBUF, | |||||
M_WAITOK | M_ZERO); | |||||
memcpy(newmap, hn_vfmap, | |||||
sizeof(struct ifnet *) * hn_vfmap_size); | |||||
free(hn_vfmap, M_DEVBUF); | |||||
hn_vfmap = newmap; | |||||
hn_vfmap_size = newsize; | |||||
} | |||||
KASSERT(hn_vfmap[ifp->if_index] == NULL, | |||||
("%s: ifindex %d was mapped to %s", | |||||
ifp->if_xname, ifp->if_index, hn_vfmap[ifp->if_index]->if_xname)); | |||||
hn_vfmap[ifp->if_index] = sc->hn_ifp; | |||||
rm_wunlock(&hn_vfmap_lock); | |||||
sc->hn_vf_ifp = ifp; | |||||
done: | |||||
HN_UNLOCK(sc); | |||||
} | |||||
static void | |||||
hn_ifnet_detevent(void *xsc, struct ifnet *ifp) | |||||
{ | |||||
struct hn_softc *sc = xsc; | |||||
HN_LOCK(sc); | |||||
if (sc->hn_vf_ifp == NULL) | |||||
goto done; | |||||
if (!hn_ismyvf(sc, ifp)) | |||||
goto done; | |||||
sc->hn_vf_ifp = NULL; | |||||
rm_wlock(&hn_vfmap_lock); | |||||
KASSERT(ifp->if_index < hn_vfmap_size, | |||||
("ifindex %d, vfmapsize %d", ifp->if_index, hn_vfmap_size)); | |||||
if (hn_vfmap[ifp->if_index] != NULL) { | |||||
KASSERT(hn_vfmap[ifp->if_index] == sc->hn_ifp, | |||||
("%s: ifindex %d was mapped to %s", | |||||
ifp->if_xname, ifp->if_index, | |||||
hn_vfmap[ifp->if_index]->if_xname)); | |||||
hn_vfmap[ifp->if_index] = NULL; | |||||
} | |||||
rm_wunlock(&hn_vfmap_lock); | |||||
done: | |||||
HN_UNLOCK(sc); | |||||
} | |||||
/* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */ | /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */ | ||||
static const struct hyperv_guid g_net_vsc_device_type = { | static const struct hyperv_guid g_net_vsc_device_type = { | ||||
.hv_guid = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, | .hv_guid = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, | ||||
0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E} | 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E} | ||||
}; | }; | ||||
static int | static int | ||||
hn_probe(device_t dev) | hn_probe(device_t dev) | ||||
▲ Show 20 Lines • Show All 224 Lines • ▼ Show 20 Lines | SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "agg_pkts", | ||||
"0 -- disable, -1 -- auto"); | "0 -- disable, -1 -- auto"); | ||||
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "polling", | SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "polling", | ||||
CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, | CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, | ||||
hn_polling_sysctl, "I", | hn_polling_sysctl, "I", | ||||
"Polling frequency: [100,1000000], 0 disable polling"); | "Polling frequency: [100,1000000], 0 disable polling"); | ||||
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf", | SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "vf", | ||||
CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, | CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, | ||||
hn_vf_sysctl, "A", "Virtual Function's name"); | hn_vf_sysctl, "A", "Virtual Function's name"); | ||||
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxvf", | |||||
CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, | |||||
hn_rxvf_sysctl, "A", "activated Virtual Function's name"); | |||||
/* | /* | ||||
* Setup the ifmedia, which has been initialized earlier. | * Setup the ifmedia, which has been initialized earlier. | ||||
*/ | */ | ||||
ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL); | ifmedia_add(&sc->hn_media, IFM_ETHER | IFM_AUTO, 0, NULL); | ||||
ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO); | ifmedia_set(&sc->hn_media, IFM_ETHER | IFM_AUTO); | ||||
/* XXX ifmedia_set really should do this for us */ | /* XXX ifmedia_set really should do this for us */ | ||||
sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media; | sc->hn_media.ifm_media = sc->hn_media.ifm_cur->ifm_media; | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | #endif | ||||
/* | /* | ||||
* Kick off link status check. | * Kick off link status check. | ||||
*/ | */ | ||||
sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0; | sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0; | ||||
hn_update_link_status(sc); | hn_update_link_status(sc); | ||||
sc->hn_ifnet_evthand = EVENTHANDLER_REGISTER(ifnet_event, | sc->hn_ifnet_evthand = EVENTHANDLER_REGISTER(ifnet_event, | ||||
hn_ifnet_event, sc, EVENTHANDLER_PRI_ANY); | hn_ifnet_event, sc, EVENTHANDLER_PRI_ANY); | ||||
sc->hn_ifaddr_evthand = EVENTHANDLER_REGISTER(ifaddr_event, | sc->hn_ifaddr_evthand = EVENTHANDLER_REGISTER(ifaddr_event, | ||||
hn_ifaddr_event, sc, EVENTHANDLER_PRI_ANY); | hn_ifaddr_event, sc, EVENTHANDLER_PRI_ANY); | ||||
sc->hn_ifnet_atthand = EVENTHANDLER_REGISTER(ether_ifattach_event, | |||||
hn_ifnet_attevent, sc, EVENTHANDLER_PRI_ANY); | |||||
sc->hn_ifnet_dethand = EVENTHANDLER_REGISTER(ifnet_departure_event, | |||||
hn_ifnet_detevent, sc, EVENTHANDLER_PRI_ANY); | |||||
return (0); | return (0); | ||||
failed: | failed: | ||||
if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) | if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) | ||||
hn_synth_detach(sc); | hn_synth_detach(sc); | ||||
hn_detach(dev); | hn_detach(dev); | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
hn_detach(device_t dev) | hn_detach(device_t dev) | ||||
{ | { | ||||
struct hn_softc *sc = device_get_softc(dev); | struct hn_softc *sc = device_get_softc(dev); | ||||
struct ifnet *ifp = sc->hn_ifp; | struct ifnet *ifp = sc->hn_ifp, *vf_ifp; | ||||
if (sc->hn_ifaddr_evthand != NULL) | if (sc->hn_ifaddr_evthand != NULL) | ||||
EVENTHANDLER_DEREGISTER(ifaddr_event, sc->hn_ifaddr_evthand); | EVENTHANDLER_DEREGISTER(ifaddr_event, sc->hn_ifaddr_evthand); | ||||
if (sc->hn_ifnet_evthand != NULL) | if (sc->hn_ifnet_evthand != NULL) | ||||
EVENTHANDLER_DEREGISTER(ifnet_event, sc->hn_ifnet_evthand); | EVENTHANDLER_DEREGISTER(ifnet_event, sc->hn_ifnet_evthand); | ||||
if (sc->hn_ifnet_atthand != NULL) { | |||||
EVENTHANDLER_DEREGISTER(ether_ifattach_event, | |||||
sc->hn_ifnet_atthand); | |||||
} | |||||
if (sc->hn_ifnet_dethand != NULL) { | |||||
EVENTHANDLER_DEREGISTER(ifnet_departure_event, | |||||
sc->hn_ifnet_dethand); | |||||
} | |||||
vf_ifp = sc->hn_vf_ifp; | |||||
__compiler_membar(); | |||||
if (vf_ifp != NULL) | |||||
hn_ifnet_detevent(sc, vf_ifp); | |||||
if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) { | if (sc->hn_xact != NULL && vmbus_chan_is_revoked(sc->hn_prichan)) { | ||||
/* | /* | ||||
* In case that the vmbus missed the orphan handler | * In case that the vmbus missed the orphan handler | ||||
* installation. | * installation. | ||||
*/ | */ | ||||
vmbus_xact_ctx_orphan(sc->hn_xact); | vmbus_xact_ctx_orphan(sc->hn_xact); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 875 Lines • ▼ Show 20 Lines | hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen, | ||||
const struct hn_rxinfo *info) | const struct hn_rxinfo *info) | ||||
{ | { | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
struct mbuf *m_new; | struct mbuf *m_new; | ||||
int size, do_lro = 0, do_csum = 1; | int size, do_lro = 0, do_csum = 1; | ||||
int hash_type; | int hash_type; | ||||
/* If the VF is active, inject the packet through the VF */ | /* If the VF is active, inject the packet through the VF */ | ||||
ifp = rxr->hn_vf ? rxr->hn_vf : rxr->hn_ifp; | ifp = rxr->hn_rxvf_ifp ? rxr->hn_rxvf_ifp : rxr->hn_ifp; | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { | if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { | ||||
/* | /* | ||||
* NOTE: | * NOTE: | ||||
* See the NOTE of hn_rndis_init_fixat(). This | * See the NOTE of hn_rndis_init_fixat(). This | ||||
* function can be reached, immediately after the | * function can be reached, immediately after the | ||||
* RNDIS is initialized but before the ifnet is | * RNDIS is initialized but before the ifnet is | ||||
* setup on the hn_attach() path; drop the unexpected | * setup on the hn_attach() path; drop the unexpected | ||||
▲ Show 20 Lines • Show All 958 Lines • ▼ Show 20 Lines | hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS) | ||||
snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS); | snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS); | ||||
return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req); | return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req); | ||||
} | } | ||||
static int | static int | ||||
hn_vf_sysctl(SYSCTL_HANDLER_ARGS) | hn_vf_sysctl(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct hn_softc *sc = arg1; | struct hn_softc *sc = arg1; | ||||
char vf_name[128]; | char vf_name[IFNAMSIZ + 1]; | ||||
struct ifnet *vf; | struct ifnet *vf; | ||||
HN_LOCK(sc); | HN_LOCK(sc); | ||||
vf_name[0] = '\0'; | vf_name[0] = '\0'; | ||||
vf = sc->hn_rx_ring[0].hn_vf; | vf = sc->hn_vf_ifp; | ||||
if (vf != NULL) | if (vf != NULL) | ||||
snprintf(vf_name, sizeof(vf_name), "%s", if_name(vf)); | snprintf(vf_name, sizeof(vf_name), "%s", if_name(vf)); | ||||
HN_UNLOCK(sc); | HN_UNLOCK(sc); | ||||
return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req); | return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req); | ||||
} | } | ||||
static int | static int | ||||
hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
struct hn_softc *sc = arg1; | |||||
char vf_name[IFNAMSIZ + 1]; | |||||
struct ifnet *vf; | |||||
HN_LOCK(sc); | |||||
vf_name[0] = '\0'; | |||||
vf = sc->hn_rx_ring[0].hn_rxvf_ifp; | |||||
if (vf != NULL) | |||||
snprintf(vf_name, sizeof(vf_name), "%s", if_name(vf)); | |||||
HN_UNLOCK(sc); | |||||
return sysctl_handle_string(oidp, vf_name, sizeof(vf_name), req); | |||||
} | |||||
static int | |||||
hn_vflist_sysctl(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
struct rm_priotracker pt; | |||||
struct sbuf *sb; | |||||
int error, i; | |||||
bool first; | |||||
error = sysctl_wire_old_buffer(req, 0); | |||||
if (error != 0) | |||||
return (error); | |||||
sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); | |||||
if (sb == NULL) | |||||
return (ENOMEM); | |||||
rm_rlock(&hn_vfmap_lock, &pt); | |||||
first = true; | |||||
for (i = 0; i < hn_vfmap_size; ++i) { | |||||
struct ifnet *ifp; | |||||
if (hn_vfmap[i] == NULL) | |||||
continue; | |||||
ifp = ifnet_byindex(i); | |||||
if (ifp != NULL) { | |||||
if (first) | |||||
sbuf_printf(sb, "%s", ifp->if_xname); | |||||
else | |||||
sbuf_printf(sb, " %s", ifp->if_xname); | |||||
first = false; | |||||
} | |||||
} | |||||
rm_runlock(&hn_vfmap_lock, &pt); | |||||
error = sbuf_finish(sb); | |||||
sbuf_delete(sb); | |||||
return (error); | |||||
} | |||||
static int | |||||
hn_vfmap_sysctl(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
struct rm_priotracker pt; | |||||
struct sbuf *sb; | |||||
int error, i; | |||||
bool first; | |||||
error = sysctl_wire_old_buffer(req, 0); | |||||
if (error != 0) | |||||
return (error); | |||||
sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); | |||||
if (sb == NULL) | |||||
return (ENOMEM); | |||||
rm_rlock(&hn_vfmap_lock, &pt); | |||||
first = true; | |||||
for (i = 0; i < hn_vfmap_size; ++i) { | |||||
struct ifnet *ifp, *hn_ifp; | |||||
hn_ifp = hn_vfmap[i]; | |||||
if (hn_ifp == NULL) | |||||
continue; | |||||
ifp = ifnet_byindex(i); | |||||
if (ifp != NULL) { | |||||
if (first) { | |||||
sbuf_printf(sb, "%s:%s", ifp->if_xname, | |||||
hn_ifp->if_xname); | |||||
} else { | |||||
sbuf_printf(sb, " %s:%s", ifp->if_xname, | |||||
hn_ifp->if_xname); | |||||
} | |||||
first = false; | |||||
} | |||||
} | |||||
rm_runlock(&hn_vfmap_lock, &pt); | |||||
error = sbuf_finish(sb); | |||||
sbuf_delete(sb); | |||||
return (error); | |||||
} | |||||
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; | ||||
const struct tcphdr *th; | const struct tcphdr *th; | ||||
int thoff; /* TCP data offset */ | int thoff; /* TCP data offset */ | ||||
len = hoff + sizeof(struct ip); | len = hoff + sizeof(struct ip); | ||||
▲ Show 20 Lines • Show All 2,499 Lines • ▼ Show 20 Lines | default: | ||||
pkt->cph_type); | pkt->cph_type); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
hn_chan_rollup(rxr, rxr->hn_txr); | hn_chan_rollup(rxr, rxr->hn_txr); | ||||
} | } | ||||
static void | static void | ||||
hn_tx_taskq_create(void *arg __unused) | hn_sysinit(void *arg __unused) | ||||
{ | { | ||||
int i; | int i; | ||||
/* | /* | ||||
* Initialize VF map. | |||||
*/ | |||||
rm_init_flags(&hn_vfmap_lock, "hn_vfmap", RM_SLEEPABLE); | |||||
hn_vfmap_size = HN_VFMAP_SIZE_DEF; | |||||
hn_vfmap = malloc(sizeof(struct ifnet *) * hn_vfmap_size, M_DEVBUF, | |||||
M_WAITOK | M_ZERO); | |||||
/* | |||||
* Fix the # of TX taskqueues. | * Fix the # of TX taskqueues. | ||||
*/ | */ | ||||
if (hn_tx_taskq_cnt <= 0) | if (hn_tx_taskq_cnt <= 0) | ||||
hn_tx_taskq_cnt = 1; | hn_tx_taskq_cnt = 1; | ||||
else if (hn_tx_taskq_cnt > mp_ncpus) | else if (hn_tx_taskq_cnt > mp_ncpus) | ||||
hn_tx_taskq_cnt = mp_ncpus; | hn_tx_taskq_cnt = mp_ncpus; | ||||
/* | /* | ||||
Show All 19 Lines | hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *), | ||||
M_DEVBUF, M_WAITOK); | M_DEVBUF, M_WAITOK); | ||||
for (i = 0; i < hn_tx_taskq_cnt; ++i) { | for (i = 0; i < hn_tx_taskq_cnt; ++i) { | ||||
hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK, | hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK, | ||||
taskqueue_thread_enqueue, &hn_tx_taskque[i]); | taskqueue_thread_enqueue, &hn_tx_taskque[i]); | ||||
taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET, | taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET, | ||||
"hn tx%d", i); | "hn tx%d", i); | ||||
} | } | ||||
} | } | ||||
SYSINIT(hn_txtq_create, SI_SUB_DRIVERS, SI_ORDER_SECOND, | SYSINIT(hn_sysinit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysinit, NULL); | ||||
hn_tx_taskq_create, NULL); | |||||
static void | static void | ||||
hn_tx_taskq_destroy(void *arg __unused) | hn_sysuninit(void *arg __unused) | ||||
{ | { | ||||
if (hn_tx_taskque != NULL) { | if (hn_tx_taskque != NULL) { | ||||
int i; | int i; | ||||
for (i = 0; i < hn_tx_taskq_cnt; ++i) | for (i = 0; i < hn_tx_taskq_cnt; ++i) | ||||
taskqueue_free(hn_tx_taskque[i]); | taskqueue_free(hn_tx_taskque[i]); | ||||
free(hn_tx_taskque, M_DEVBUF); | free(hn_tx_taskque, M_DEVBUF); | ||||
} | } | ||||
if (hn_vfmap != NULL) | |||||
free(hn_vfmap, M_DEVBUF); | |||||
rm_destroy(&hn_vfmap_lock); | |||||
} | } | ||||
SYSUNINIT(hn_txtq_destroy, SI_SUB_DRIVERS, SI_ORDER_SECOND, | SYSUNINIT(hn_sysuninit, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_sysuninit, NULL); | ||||
hn_tx_taskq_destroy, NULL); |