diff options
| -rw-r--r-- | sys/dev/ixgbe/if_ixv.c | 49 | ||||
| -rw-r--r-- | sys/dev/ixgbe/if_sriov.c | 116 | ||||
| -rw-r--r-- | sys/dev/ixgbe/ixgbe.h | 2 | ||||
| -rw-r--r-- | sys/dev/ixgbe/ixgbe_sriov.h | 3 | ||||
| -rw-r--r-- | sys/dev/ixgbe/ixgbe_vf.c | 2 |
5 files changed, 144 insertions, 28 deletions
diff --git a/sys/dev/ixgbe/if_ixv.c b/sys/dev/ixgbe/if_ixv.c index f5af6a53da49..788dd506669d 100644 --- a/sys/dev/ixgbe/if_ixv.c +++ b/sys/dev/ixgbe/if_ixv.c @@ -114,6 +114,7 @@ static void ixv_configure_ivars(struct ixgbe_softc *); static void ixv_if_enable_intr(if_ctx_t); static void ixv_if_disable_intr(if_ctx_t); static void ixv_if_multi_set(if_ctx_t); +static int ixv_if_promisc_set(if_ctx_t, int); static void ixv_if_register_vlan(if_ctx_t, u16); static void ixv_if_unregister_vlan(if_ctx_t, u16); @@ -174,6 +175,7 @@ static device_method_t ixv_if_methods[] = { DEVMETHOD(ifdi_queues_free, ixv_if_queues_free), DEVMETHOD(ifdi_update_admin_status, ixv_if_update_admin_status), DEVMETHOD(ifdi_multi_set, ixv_if_multi_set), + DEVMETHOD(ifdi_promisc_set, ixv_if_promisc_set), DEVMETHOD(ifdi_mtu_set, ixv_if_mtu_set), DEVMETHOD(ifdi_media_status, ixv_if_media_status), DEVMETHOD(ifdi_media_change, ixv_if_media_change), @@ -847,6 +849,7 @@ ixv_negotiate_api(struct ixgbe_softc *sc) { struct ixgbe_hw *hw = &sc->hw; int mbx_api[] = { + ixgbe_mbox_api_13, ixgbe_mbox_api_12, ixgbe_mbox_api_11, ixgbe_mbox_api_10, @@ -863,6 +866,40 @@ ixv_negotiate_api(struct ixgbe_softc *sc) return (EINVAL); } /* ixv_negotiate_api */ +static int +ixv_update_xcast_mode(struct ixgbe_softc *sc, int flags) +{ + if_t ifp; + int mode; + + ifp = iflib_get_ifp(sc->ctx); + if (flags & IFF_PROMISC) + mode = IXGBEVF_XCAST_MODE_PROMISC; + else if ((flags & IFF_ALLMULTI) != 0 || + if_llmaddr_count(ifp) > IXGBE_MAX_VF_MC) + mode = IXGBEVF_XCAST_MODE_ALLMULTI; + else if (if_llmaddr_count(ifp) != 0) + mode = IXGBEVF_XCAST_MODE_MULTI; + else + mode = IXGBEVF_XCAST_MODE_NONE; + return (ixgbevf_update_xcast_mode(&sc->hw, mode)); +} + +static int +ixv_if_promisc_set(if_ctx_t ctx, int flags) +{ + struct ixgbe_softc *sc; + if_t ifp; + + sc = iflib_get_softc(ctx); + ifp = iflib_get_ifp(ctx); + if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) + return (0); + if (ixv_update_xcast_mode(sc, flags) != IXGBE_SUCCESS) + return (EOPNOTSUPP); + return (0); +} /* ixv_if_promisc_set */ + static u_int ixv_if_multi_set_cb(void *cb_arg, struct sockaddr_dl *addr, u_int cnt) @@ -889,7 +926,7 @@ ixv_if_multi_set(if_ctx_t ctx) struct ixgbe_softc *sc = iflib_get_softc(ctx); u8 *update_ptr; if_t ifp = iflib_get_ifp(ctx); - int mcnt = 0; + int error, mcnt = 0; IOCTL_DEBUGOUT("ixv_if_multi_set: begin"); @@ -899,6 +936,16 @@ ixv_if_multi_set(if_ctx_t ctx) sc->hw.mac.ops.update_mc_addr_list(&sc->hw, update_ptr, mcnt, ixv_mc_array_itr, true); + error = ixv_update_xcast_mode(sc, if_getflags(ifp)); + if (mcnt > IXGBE_MAX_VF_MC && error != IXGBE_SUCCESS) { + if (!sc->vf_mcast_overflow_warned) + device_printf(sc->dev, + "PF rejected all-multicast fallback; only %d " + "multicast addresses are active\n", + IXGBE_MAX_VF_MC); + sc->vf_mcast_overflow_warned = true; + } else if (mcnt <= IXGBE_MAX_VF_MC) + sc->vf_mcast_overflow_warned = false; } /* ixv_if_multi_set */ /************************************************************************ diff --git a/sys/dev/ixgbe/if_sriov.c b/sys/dev/ixgbe/if_sriov.c index 2a5fd6a864ee..903ed72d6e2f 100644 --- a/sys/dev/ixgbe/if_sriov.c +++ b/sys/dev/ixgbe/if_sriov.c @@ -342,11 +342,11 @@ ixgbe_vf_vlan_record(struct ixgbe_vf *vf, uint16_t tag, bool enable) } static void -ixgbe_vf_configure_default_vlan(struct ixgbe_softc *sc, - struct ixgbe_vf *vf) +ixgbe_vf_configure_vmolr(struct ixgbe_softc *sc, struct ixgbe_vf *vf) { struct ixgbe_hw *hw; uint32_t vmolr, vmvir; + uint8_t xcast_mode; uint16_t tag; hw = &sc->hw; @@ -354,11 +354,9 @@ ixgbe_vf_configure_default_vlan(struct ixgbe_softc *sc, vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf->pool)); - /* Do not receive packets that pass inexact filters. */ - vmolr &= ~(IXGBE_VMOLR_ROMPE | IXGBE_VMOLR_ROPE); - - /* Disable Multicast Promicuous Mode. */ - vmolr &= ~IXGBE_VMOLR_MPE; + vmolr &= ~(IXGBE_VMOLR_UPE | IXGBE_VMOLR_ROMPE | + IXGBE_VMOLR_ROPE | IXGBE_VMOLR_MPE | IXGBE_VMOLR_VPE | + IXGBE_VMOLR_AUPE); /* Accept broadcasts. */ vmolr |= IXGBE_VMOLR_BAM; @@ -376,9 +374,28 @@ ixgbe_vf_configure_default_vlan(struct ixgbe_softc *sc, /* Tag all traffic with provided vlan tag. */ vmvir = (tag | IXGBE_VMVIR_VLANA_DEFAULT); } + + xcast_mode = vf->xcast_mode; + if ((vf->api_ver == IXGBE_API_VER_UNKNOWN || + vf->api_ver < IXGBE_API_VER_1_2) && vf->num_mc_hashes != 0) + xcast_mode = IXGBEVF_XCAST_MODE_MULTI; + switch (xcast_mode) { + case IXGBEVF_XCAST_MODE_PROMISC: + vmolr |= IXGBE_VMOLR_UPE; + /* FALLTHROUGH */ + case IXGBEVF_XCAST_MODE_ALLMULTI: + vmolr |= IXGBE_VMOLR_MPE; + /* FALLTHROUGH */ + case IXGBEVF_XCAST_MODE_MULTI: + vmolr |= IXGBE_VMOLR_ROMPE; + break; + case IXGBEVF_XCAST_MODE_NONE: + default: + break; + } IXGBE_WRITE_REG(hw, IXGBE_VMOLR(vf->pool), vmolr); IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf->pool), vmvir); -} /* ixgbe_vf_configure_default_vlan */ +} /* ixgbe_vf_configure_vmolr */ static void ixgbe_vf_clear_vlans(struct ixgbe_softc *sc, struct ixgbe_vf *vf, @@ -416,7 +433,7 @@ ixgbe_vf_reset_vlan(struct ixgbe_softc *sc, struct ixgbe_vf *vf, if (error == IXGBE_SUCCESS) ixgbe_vf_vlan_record(vf, vf->default_vlan, true); } - ixgbe_vf_configure_default_vlan(sc, vf); + ixgbe_vf_configure_vmolr(sc, vf); return (error); } @@ -472,15 +489,15 @@ ixgbe_process_vf_reset(struct ixgbe_softc *sc, struct ixgbe_vf *vf) bool rebuild_mta; s32 error; + rebuild_mta = vf->num_mc_hashes != 0; + vf->xcast_mode = IXGBEVF_XCAST_MODE_NONE; + vf->num_mc_hashes = 0; + bzero(vf->mc_hash, sizeof(vf->mc_hash)); error = ixgbe_vf_reset_vlan(sc, vf, true); if (error != IXGBE_SUCCESS) device_printf(sc->dev, "VF %u default VLAN restore failed: %d\n", vf->pool, error); - - rebuild_mta = vf->num_mc_hashes != 0; - vf->num_mc_hashes = 0; - bzero(vf->mc_hash, sizeof(vf->mc_hash)); if (rebuild_mta) ixgbe_iov_rebuild_mta(sc); @@ -609,24 +626,21 @@ ixgbe_vf_set_mc_addr(struct ixgbe_softc *sc, struct ixgbe_vf *vf, u32 *msg) { u16 *list = (u16*)&msg[1]; int entries; - u32 vmolr; - entries = (msg[0] & IXGBE_VT_MSGINFO_MASK) >> IXGBE_VT_MSGINFO_SHIFT; + entries = (msg[0] & IXGBE_VT_MSGINFO_MASK) >> + IXGBE_VT_MSGINFO_SHIFT; entries = min(entries, IXGBE_MAX_VF_MC); - vmolr = IXGBE_READ_REG(&sc->hw, IXGBE_VMOLR(vf->pool)); - vmolr &= ~IXGBE_VMOLR_ROMPE; - IXGBE_WRITE_REG(&sc->hw, IXGBE_VMOLR(vf->pool), vmolr); - bzero(vf->mc_hash, sizeof(vf->mc_hash)); bcopy(list, vf->mc_hash, entries * sizeof(*list)); vf->num_mc_hashes = entries; + if (entries != 0 && vf->xcast_mode == IXGBEVF_XCAST_MODE_NONE) + vf->xcast_mode = IXGBEVF_XCAST_MODE_MULTI; + else if (entries == 0 && + vf->xcast_mode == IXGBEVF_XCAST_MODE_MULTI) + vf->xcast_mode = IXGBEVF_XCAST_MODE_NONE; ixgbe_iov_rebuild_mta(sc); - - if (entries != 0) { - vmolr |= IXGBE_VMOLR_ROMPE; - IXGBE_WRITE_REG(&sc->hw, IXGBE_VMOLR(vf->pool), vmolr); - } + ixgbe_vf_configure_vmolr(sc, vf); ixgbe_send_vf_success(sc, vf, msg[0]); } /* ixgbe_vf_set_mc_addr */ @@ -730,6 +744,8 @@ ixgbe_vf_api_negotiate(struct ixgbe_softc *sc, struct ixgbe_vf *vf, switch (msg[1]) { case IXGBE_API_VER_1_0: case IXGBE_API_VER_1_1: + case IXGBE_API_VER_1_2: + case IXGBE_API_VER_1_3: vf->api_ver = msg[1]; ixgbe_send_vf_success(sc, vf, msg[0]); break; @@ -740,6 +756,47 @@ ixgbe_vf_api_negotiate(struct ixgbe_softc *sc, struct ixgbe_vf *vf, } } /* ixgbe_vf_api_negotiate */ +static void +ixgbe_vf_update_xcast_mode(struct ixgbe_softc *sc, struct ixgbe_vf *vf, + uint32_t *msg) +{ + struct ixgbe_hw *hw; + uint32_t mode; + + hw = &sc->hw; + mode = msg[1]; + switch (vf->api_ver) { + case IXGBE_API_VER_1_2: + if (mode == IXGBEVF_XCAST_MODE_PROMISC) + goto failure; + break; + case IXGBE_API_VER_1_3: + break; + default: + goto failure; + } + if (mode > IXGBEVF_XCAST_MODE_PROMISC) + goto failure; + if (mode > IXGBEVF_XCAST_MODE_MULTI && + !(vf->flags & IXGBE_VF_ALLOW_PROMISC)) + goto failure; + if (mode == IXGBEVF_XCAST_MODE_PROMISC && + (hw->mac.type <= ixgbe_mac_82599EB || + !(IXGBE_READ_REG(hw, IXGBE_FCTRL) & IXGBE_FCTRL_UPE))) + goto failure; + + vf->xcast_mode = mode; + ixgbe_vf_configure_vmolr(sc, vf); + msg[0] &= IXGBE_VT_MSG_MASK; + msg[0] |= IXGBE_VT_MSGTYPE_SUCCESS | IXGBE_VT_MSGTYPE_CTS; + msg[1] = mode; + ixgbe_write_mbx(hw, msg, 2, vf->pool); + return; + +failure: + ixgbe_send_vf_failure(sc, vf, msg[0]); +} /* ixgbe_vf_update_xcast_mode */ + static void ixgbe_vf_get_queues(struct ixgbe_softc *sc, struct ixgbe_vf *vf, @@ -824,6 +881,9 @@ ixgbe_process_vf_msg(if_ctx_t ctx, struct ixgbe_vf *vf) case IXGBE_VF_GET_QUEUES: ixgbe_vf_get_queues(sc, vf, msg); break; + case IXGBE_VF_UPDATE_XCAST_MODE: + ixgbe_vf_update_xcast_mode(sc, vf, msg); + break; default: ixgbe_send_vf_failure(sc, vf, msg[0]); } @@ -982,11 +1042,13 @@ ixgbe_init_vf(struct ixgbe_softc *sc, struct ixgbe_vf *vf) pfmbimr |= IXGBE_VF_BIT(vf->pool); IXGBE_WRITE_REG(hw, IXGBE_PFMBIMR(vf_index), pfmbimr); + vf->xcast_mode = IXGBEVF_XCAST_MODE_NONE; + vf->api_ver = IXGBE_API_VER_UNKNOWN; + vf->num_mc_hashes = 0; + bzero(vf->mc_hash, sizeof(vf->mc_hash)); error = ixgbe_vf_reset_vlan(sc, vf, false); if (error != IXGBE_SUCCESS) return (error); - vf->num_mc_hashes = 0; - bzero(vf->mc_hash, sizeof(vf->mc_hash)); if (ixgbe_validate_mac_addr(vf->ether_addr) == 0) { ixgbe_set_rar(&sc->hw, vf->rar_index, @@ -1114,6 +1176,8 @@ ixgbe_if_iov_vf_add(if_ctx_t ctx, u16 vfnum, const nvlist_t *config) ixgbe_update_max_frame(sc, vf->maximum_frame_size); if (nvlist_get_bool(config, "mac-anti-spoof")) vf->flags |= IXGBE_VF_ANTI_SPOOF; + if (nvlist_get_bool(config, "allow-promisc")) + vf->flags |= IXGBE_VF_ALLOW_PROMISC; if (nvlist_exists_binary(config, "mac-addr")) { mac = nvlist_get_binary(config, "mac-addr", NULL); diff --git a/sys/dev/ixgbe/ixgbe.h b/sys/dev/ixgbe/ixgbe.h index 26513a0ba965..330d1a8a2cb3 100644 --- a/sys/dev/ixgbe/ixgbe.h +++ b/sys/dev/ixgbe/ixgbe.h @@ -357,6 +357,7 @@ struct ixgbe_vf { uint16_t num_vlans; uint16_t default_vlan; uint16_t api_ver; + uint8_t xcast_mode; }; /* Our softc structure */ @@ -397,6 +398,7 @@ struct ixgbe_softc { * to repopulate it. */ u32 shadow_vfta[IXGBE_VFTA_SIZE]; + bool vf_mcast_overflow_warned; /* Info about the interface */ int advertise; /* link speeds */ diff --git a/sys/dev/ixgbe/ixgbe_sriov.h b/sys/dev/ixgbe/ixgbe_sriov.h index bae3f25f7d71..491a708b6f41 100644 --- a/sys/dev/ixgbe/ixgbe_sriov.h +++ b/sys/dev/ixgbe/ixgbe_sriov.h @@ -48,6 +48,7 @@ #define IXGBE_VF_CAP_VLAN (1 << 2) /* VF is permitted to join vlans. */ #define IXGBE_VF_ACTIVE (1 << 3) /* VF is active. */ #define IXGBE_VF_ANTI_SPOOF (1 << 4) /* Enforce source identity. */ +#define IXGBE_VF_ALLOW_PROMISC (1 << 5) /* VF may request promiscuity. */ #define IXGBE_VF_INDEX(vmdq) ((vmdq) / 32) #define IXGBE_VF_BIT(vmdq) (1 << ((vmdq) % 32)) @@ -61,6 +62,8 @@ #define IXGBE_API_VER_1_0 0 #define IXGBE_API_VER_2_0 1 /* Solaris API. Not supported. */ #define IXGBE_API_VER_1_1 2 +#define IXGBE_API_VER_1_2 3 +#define IXGBE_API_VER_1_3 4 #define IXGBE_API_VER_UNKNOWN UINT16_MAX #define IXGBE_NO_VM 0 diff --git a/sys/dev/ixgbe/ixgbe_vf.c b/sys/dev/ixgbe/ixgbe_vf.c index 89bf5929260d..5f65ee038753 100644 --- a/sys/dev/ixgbe/ixgbe_vf.c +++ b/sys/dev/ixgbe/ixgbe_vf.c @@ -411,7 +411,7 @@ s32 ixgbe_update_mc_addr_list_vf(struct ixgbe_hw *hw, u8 *mc_addr_list, DEBUGOUT1("MC Addr Count = %d\n", mc_addr_count); - cnt = (mc_addr_count > 30) ? 30 : mc_addr_count; + cnt = min(mc_addr_count, IXGBE_MAX_VF_MC); msgbuf[0] = IXGBE_VF_SET_MULTICAST; msgbuf[0] |= cnt << IXGBE_VT_MSGINFO_SHIFT; |
