Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/hyperv/netvsc/if_hn.c
Show First 20 Lines • Show All 216 Lines • ▼ Show 20 Lines | |||||
struct hn_rxinfo { | struct hn_rxinfo { | ||||
uint32_t vlan_info; | uint32_t vlan_info; | ||||
uint32_t csum_info; | uint32_t csum_info; | ||||
uint32_t hash_info; | uint32_t hash_info; | ||||
uint32_t hash_value; | uint32_t hash_value; | ||||
}; | }; | ||||
struct hn_update_vf { | struct hn_rxvf_setarg { | ||||
struct hn_rx_ring *rxr; | struct hn_rx_ring *rxr; | ||||
struct ifnet *vf; | struct ifnet *vf_ifp; | ||||
}; | }; | ||||
#define HN_RXINFO_VLAN 0x0001 | #define HN_RXINFO_VLAN 0x0001 | ||||
#define HN_RXINFO_CSUM 0x0002 | #define HN_RXINFO_CSUM 0x0002 | ||||
#define HN_RXINFO_HASHINF 0x0004 | #define HN_RXINFO_HASHINF 0x0004 | ||||
#define HN_RXINFO_HASHVAL 0x0008 | #define HN_RXINFO_HASHVAL 0x0008 | ||||
#define HN_RXINFO_ALL \ | #define HN_RXINFO_ALL \ | ||||
(HN_RXINFO_VLAN | \ | (HN_RXINFO_VLAN | \ | ||||
Show All 23 Lines | |||||
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_ifnet_event(void *, struct ifnet *, int); | ||||
static void hn_ifaddr_event(void *, struct ifnet *); | static void hn_ifaddr_event(void *, struct ifnet *); | ||||
static void hn_ifnet_attevent(void *, struct ifnet *); | static void hn_ifnet_attevent(void *, struct ifnet *); | ||||
static void hn_ifnet_detevent(void *, struct ifnet *); | static void hn_ifnet_detevent(void *, struct ifnet *); | ||||
static bool hn_ismyvf(const struct hn_softc *, | |||||
const struct ifnet *); | |||||
static void hn_rxvf_change(struct hn_softc *, | |||||
struct ifnet *, bool); | |||||
static void hn_rxvf_set(struct hn_softc *, struct ifnet *); | |||||
static void hn_rxvf_set_task(void *, int); | |||||
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 20 Lines • Show All 521 Lines • ▼ Show 20 Lines | |||||
hn_rxfilter_config(struct hn_softc *sc) | hn_rxfilter_config(struct hn_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->hn_ifp; | struct ifnet *ifp = sc->hn_ifp; | ||||
uint32_t filter; | uint32_t filter; | ||||
HN_LOCK_ASSERT(sc); | HN_LOCK_ASSERT(sc); | ||||
if ((ifp->if_flags & IFF_PROMISC) || | if ((ifp->if_flags & IFF_PROMISC) || | ||||
(sc->hn_flags & HN_FLAG_VF)) { | (sc->hn_flags & HN_FLAG_RXVF)) { | ||||
filter = NDIS_PACKET_TYPE_PROMISCUOUS; | filter = NDIS_PACKET_TYPE_PROMISCUOUS; | ||||
} else { | } else { | ||||
filter = NDIS_PACKET_TYPE_DIRECTED; | filter = NDIS_PACKET_TYPE_DIRECTED; | ||||
if (ifp->if_flags & IFF_BROADCAST) | if (ifp->if_flags & IFF_BROADCAST) | ||||
filter |= NDIS_PACKET_TYPE_BROADCAST; | filter |= NDIS_PACKET_TYPE_BROADCAST; | ||||
/* TODO: support multicast list */ | /* TODO: support multicast list */ | ||||
if ((ifp->if_flags & IFF_ALLMULTI) || | if ((ifp->if_flags & IFF_ALLMULTI) || | ||||
!TAILQ_EMPTY(&ifp->if_multiaddrs)) | !TAILQ_EMPTY(&ifp->if_multiaddrs)) | ||||
▲ Show 20 Lines • Show All 173 Lines • ▼ Show 20 Lines | if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) { | ||||
ifmr->ifm_active |= IFM_NONE; | ifmr->ifm_active |= IFM_NONE; | ||||
return; | return; | ||||
} | } | ||||
ifmr->ifm_status |= IFM_ACTIVE; | ifmr->ifm_status |= IFM_ACTIVE; | ||||
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_rxvf_set_task(void *xarg, int pending __unused) | ||||
{ | { | ||||
struct hn_update_vf *uv = arg; | struct hn_rxvf_setarg *arg = xarg; | ||||
uv->rxr->hn_rxvf_ifp = uv->vf; | arg->rxr->hn_rxvf_ifp = arg->vf_ifp; | ||||
} | } | ||||
static void | static void | ||||
hn_update_vf(struct hn_softc *sc, struct ifnet *vf) | hn_rxvf_set(struct hn_softc *sc, struct ifnet *vf_ifp) | ||||
{ | { | ||||
struct hn_rx_ring *rxr; | struct hn_rx_ring *rxr; | ||||
struct hn_update_vf uv; | struct hn_rxvf_setarg arg; | ||||
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_rxvf_set_task, &arg); | ||||
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; | arg.rxr = rxr; | ||||
uv.vf = vf; | arg.vf_ifp = vf_ifp; | ||||
vmbus_chan_run_task(rxr->hn_chan, &task); | vmbus_chan_run_task(rxr->hn_chan, &task); | ||||
} else { | } else { | ||||
rxr->hn_rxvf_ifp = vf; | rxr->hn_rxvf_ifp = vf_ifp; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
static __inline bool | static bool | ||||
hn_ismyvf(const struct hn_softc *sc, const struct ifnet *ifp) | hn_ismyvf(const struct hn_softc *sc, const struct ifnet *ifp) | ||||
{ | { | ||||
const struct ifnet *hn_ifp; | const struct ifnet *hn_ifp; | ||||
hn_ifp = sc->hn_ifp; | hn_ifp = sc->hn_ifp; | ||||
if (ifp == hn_ifp) | if (ifp == hn_ifp) | ||||
return (false); | return (false); | ||||
if (ifp->if_alloctype != IFT_ETHER) | if (ifp->if_alloctype != IFT_ETHER) | ||||
return (false); | 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) | ||||
return (false); | 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 (false); | ||||
return (true); | return (true); | ||||
} | } | ||||
static void | static void | ||||
hn_set_vf(struct hn_softc *sc, struct ifnet *ifp, bool vf) | hn_rxvf_change(struct hn_softc *sc, struct ifnet *ifp, bool rxvf) | ||||
{ | { | ||||
struct ifnet *hn_ifp; | struct ifnet *hn_ifp; | ||||
HN_LOCK(sc); | HN_LOCK(sc); | ||||
if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)) | if (!(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)) | ||||
goto out; | goto out; | ||||
if (!hn_ismyvf(sc, ifp)) | if (!hn_ismyvf(sc, ifp)) | ||||
goto out; | goto out; | ||||
hn_ifp = sc->hn_ifp; | hn_ifp = sc->hn_ifp; | ||||
/* Now we're sure 'ifp' is a real VF device. */ | if (rxvf) { | ||||
if (vf) { | if (sc->hn_flags & HN_FLAG_RXVF) | ||||
if (sc->hn_flags & HN_FLAG_VF) | |||||
goto out; | goto out; | ||||
sc->hn_flags |= HN_FLAG_VF; | sc->hn_flags |= HN_FLAG_RXVF; | ||||
hn_rxfilter_config(sc); | hn_rxfilter_config(sc); | ||||
} else { | } else { | ||||
if (!(sc->hn_flags & HN_FLAG_VF)) | if (!(sc->hn_flags & HN_FLAG_RXVF)) | ||||
goto out; | goto out; | ||||
sc->hn_flags &= ~HN_FLAG_VF; | sc->hn_flags &= ~HN_FLAG_RXVF; | ||||
if (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); | rxvf ? HN_NVS_DATAPATH_VF : HN_NVS_DATAPATH_SYNTHETIC); | ||||
hn_update_vf(sc, vf ? ifp : NULL); | hn_rxvf_set(sc, rxvf ? ifp : NULL); | ||||
if (vf) { | if (rxvf) { | ||||
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(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", hn_ifp->if_xname, | ||||
vf ? "VF_UP" : "VF_DOWN", NULL); | rxvf ? "VF_UP" : "VF_DOWN", NULL); | ||||
if (bootverbose) | if (bootverbose) { | ||||
if_printf(hn_ifp, "Data path is switched %s %s\n", | if_printf(hn_ifp, "datapath is switched %s %s\n", | ||||
vf ? "to" : "from", if_name(ifp)); | rxvf ? "to" : "from", ifp->if_xname); | ||||
} | |||||
out: | out: | ||||
HN_UNLOCK(sc); | HN_UNLOCK(sc); | ||||
} | } | ||||
static void | static void | ||||
hn_ifnet_event(void *arg, struct ifnet *ifp, int event) | hn_ifnet_event(void *arg, struct ifnet *ifp, int event) | ||||
{ | { | ||||
if (event != IFNET_EVENT_UP && event != IFNET_EVENT_DOWN) | if (event != IFNET_EVENT_UP && event != IFNET_EVENT_DOWN) | ||||
return; | return; | ||||
hn_rxvf_change(arg, ifp, event == IFNET_EVENT_UP); | |||||
hn_set_vf(arg, ifp, event == IFNET_EVENT_UP); | |||||
} | } | ||||
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_rxvf_change(arg, ifp, ifp->if_flags & IFF_UP); | |||||
} | } | ||||
static void | static void | ||||
hn_ifnet_attevent(void *xsc, struct ifnet *ifp) | hn_ifnet_attevent(void *xsc, struct ifnet *ifp) | ||||
{ | { | ||||
struct hn_softc *sc = xsc; | struct hn_softc *sc = xsc; | ||||
HN_LOCK(sc); | HN_LOCK(sc); | ||||
▲ Show 20 Lines • Show All 1,769 Lines • ▼ Show 20 Lines | hn_stop(struct hn_softc *sc, bool detaching) | ||||
atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); | atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); | ||||
for (i = 0; i < sc->hn_tx_ring_inuse; ++i) | for (i = 0; i < sc->hn_tx_ring_inuse; ++i) | ||||
sc->hn_tx_ring[i].hn_oactive = 0; | sc->hn_tx_ring[i].hn_oactive = 0; | ||||
/* | /* | ||||
* If the VF is active, make sure the filter is not 0, even if | * If the VF is active, make sure the filter is not 0, even if | ||||
* the synthetic NIC is down. | * the synthetic NIC is down. | ||||
*/ | */ | ||||
if (!detaching && (sc->hn_flags & HN_FLAG_VF)) | if (!detaching && (sc->hn_flags & HN_FLAG_RXVF)) | ||||
hn_rxfilter_config(sc); | hn_rxfilter_config(sc); | ||||
} | } | ||||
static void | static void | ||||
hn_init_locked(struct hn_softc *sc) | hn_init_locked(struct hn_softc *sc) | ||||
{ | { | ||||
struct ifnet *ifp = sc->hn_ifp; | struct ifnet *ifp = sc->hn_ifp; | ||||
int i; | int i; | ||||
▲ Show 20 Lines • Show All 519 Lines • ▼ Show 20 Lines | hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS) | ||||
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[IFNAMSIZ + 1]; | char vf_name[IFNAMSIZ + 1]; | ||||
struct ifnet *vf; | struct ifnet *vf_ifp; | ||||
HN_LOCK(sc); | HN_LOCK(sc); | ||||
vf_name[0] = '\0'; | vf_name[0] = '\0'; | ||||
vf = sc->hn_vf_ifp; | vf_ifp = sc->hn_vf_ifp; | ||||
if (vf != NULL) | if (vf_ifp != NULL) | ||||
snprintf(vf_name, sizeof(vf_name), "%s", if_name(vf)); | snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname); | ||||
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) | hn_rxvf_sysctl(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct hn_softc *sc = arg1; | struct hn_softc *sc = arg1; | ||||
char vf_name[IFNAMSIZ + 1]; | char vf_name[IFNAMSIZ + 1]; | ||||
struct ifnet *vf; | struct ifnet *vf_ifp; | ||||
HN_LOCK(sc); | HN_LOCK(sc); | ||||
vf_name[0] = '\0'; | vf_name[0] = '\0'; | ||||
vf = sc->hn_rx_ring[0].hn_rxvf_ifp; | vf_ifp = sc->hn_rx_ring[0].hn_rxvf_ifp; | ||||
if (vf != NULL) | if (vf_ifp != NULL) | ||||
snprintf(vf_name, sizeof(vf_name), "%s", if_name(vf)); | snprintf(vf_name, sizeof(vf_name), "%s", vf_ifp->if_xname); | ||||
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_vflist_sysctl(SYSCTL_HANDLER_ARGS) | hn_vflist_sysctl(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct rm_priotracker pt; | struct rm_priotracker pt; | ||||
▲ Show 20 Lines • Show All 1,968 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
hn_suspend(struct hn_softc *sc) | hn_suspend(struct hn_softc *sc) | ||||
{ | { | ||||
/* Disable polling. */ | /* Disable polling. */ | ||||
hn_polling(sc, 0); | hn_polling(sc, 0); | ||||
if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) || | if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) || | ||||
(sc->hn_flags & HN_FLAG_VF)) | (sc->hn_flags & HN_FLAG_RXVF)) | ||||
hn_suspend_data(sc); | hn_suspend_data(sc); | ||||
hn_suspend_mgmt(sc); | hn_suspend_mgmt(sc); | ||||
} | } | ||||
static void | static void | ||||
hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt) | hn_resume_tx(struct hn_softc *sc, int tx_ring_cnt) | ||||
{ | { | ||||
int i; | int i; | ||||
▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | else | ||||
hn_update_link_status(sc); | hn_update_link_status(sc); | ||||
} | } | ||||
static void | static void | ||||
hn_resume(struct hn_softc *sc) | hn_resume(struct hn_softc *sc) | ||||
{ | { | ||||
if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) || | if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) || | ||||
(sc->hn_flags & HN_FLAG_VF)) | (sc->hn_flags & HN_FLAG_RXVF)) | ||||
hn_resume_data(sc); | hn_resume_data(sc); | ||||
/* | /* | ||||
* When the VF is activated, the synthetic interface is changed | * When the VF is activated, the synthetic interface is changed | ||||
* to DOWN in hn_set_vf(). Here, if the VF is still active, we | * to DOWN in hn_rxvf_change(). Here, if the VF is still active, | ||||
* don't call hn_resume_mgmt() until the VF is deactivated in | * we don't call hn_resume_mgmt() until the VF is deactivated in | ||||
* hn_set_vf(). | * hn_rxvf_change(). | ||||
*/ | */ | ||||
if (!(sc->hn_flags & HN_FLAG_VF)) | if (!(sc->hn_flags & HN_FLAG_RXVF)) | ||||
hn_resume_mgmt(sc); | hn_resume_mgmt(sc); | ||||
/* | /* | ||||
* Re-enable polling if this interface is running and | * Re-enable polling if this interface is running and | ||||
* the polling is requested. | * the polling is requested. | ||||
*/ | */ | ||||
if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->hn_pollhz > 0) | if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->hn_pollhz > 0) | ||||
hn_polling(sc, sc->hn_pollhz); | hn_polling(sc, sc->hn_pollhz); | ||||
▲ Show 20 Lines • Show All 584 Lines • Show Last 20 Lines |