Module Name: src Committed By: yamaguchi Date: Fri Jan 31 02:16:26 UTC 2020
Modified Files: src/sys/dev/pci: if_ixl.c if_ixlvar.h Log Message: Add media and flow changes support for ixl(4) To generate a diff of this commit: cvs rdiff -u -r1.30 -r1.31 src/sys/dev/pci/if_ixl.c cvs rdiff -u -r1.4 -r1.5 src/sys/dev/pci/if_ixlvar.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/pci/if_ixl.c diff -u src/sys/dev/pci/if_ixl.c:1.30 src/sys/dev/pci/if_ixl.c:1.31 --- src/sys/dev/pci/if_ixl.c:1.30 Fri Jan 31 02:11:06 2020 +++ src/sys/dev/pci/if_ixl.c Fri Jan 31 02:16:26 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: if_ixl.c,v 1.30 2020/01/31 02:11:06 yamaguchi Exp $ */ +/* $NetBSD: if_ixl.c,v 1.31 2020/01/31 02:16:26 yamaguchi Exp $ */ /* * Copyright (c) 2013-2015, Intel Corporation @@ -634,6 +634,13 @@ struct ixl_softc { struct ifmedia sc_media; uint64_t sc_media_status; uint64_t sc_media_active; + uint64_t sc_phy_types; + uint8_t sc_phy_abilities; + uint8_t sc_phy_linkspeed; + uint8_t sc_phy_fec_cfg; + uint16_t sc_eee_cap; + uint32_t sc_eeer_val; + uint8_t sc_d3_lpan; kmutex_t sc_cfg_lock; enum i40e_mac_type sc_mac_type; uint32_t sc_rss_table_size; @@ -786,7 +793,9 @@ static int ixl_lldp_shut(struct ixl_soft static int ixl_get_mac(struct ixl_softc *); static int ixl_get_switch_config(struct ixl_softc *); static int ixl_phy_mask_ints(struct ixl_softc *); -static int ixl_get_phy_types(struct ixl_softc *, uint64_t *); +static int ixl_get_phy_info(struct ixl_softc *); +static int ixl_set_phy_config(struct ixl_softc *, uint8_t, uint8_t, bool); +static int ixl_set_phy_autoselect(struct ixl_softc *); static int ixl_restart_an(struct ixl_softc *); static int ixl_hmc(struct ixl_softc *); static void ixl_hmc_free(struct ixl_softc *); @@ -797,6 +806,8 @@ static void ixl_get_link_status(void *); static int ixl_get_link_status_poll(struct ixl_softc *); static int ixl_set_link_status(struct ixl_softc *, const struct ixl_aq_desc *); +static uint64_t ixl_search_link_speed(uint8_t); +static uint8_t ixl_search_baudrate(uint64_t); static void ixl_config_rss(struct ixl_softc *); static int ixl_add_macvlan(struct ixl_softc *, const uint8_t *, uint16_t, uint16_t); @@ -813,7 +824,7 @@ static int ixl_match(device_t, cfdata_t, static void ixl_attach(device_t, device_t, void *); static int ixl_detach(device_t, int); -static void ixl_media_add(struct ixl_softc *, uint64_t); +static void ixl_media_add(struct ixl_softc *); static int ixl_media_change(struct ifnet *); static void ixl_media_status(struct ifnet *, struct ifmediareq *); static void ixl_watchdog(struct ifnet *); @@ -1081,7 +1092,6 @@ ixl_attach(device_t parent, device_t sel struct ifnet *ifp; pcireg_t memtype; uint32_t firstq, port, ari, func; - uint64_t phy_types = 0; char xnamebuf[32]; int tries, rv; @@ -1280,8 +1290,8 @@ ixl_attach(device_t parent, device_t sel goto free_hmc; } - if (ixl_get_phy_types(sc, &phy_types) != 0) { - /* error printed by ixl_get_phy_abilities */ + if (ixl_get_phy_info(sc) != 0) { + /* error printed by ixl_get_phy_info */ goto free_hmc; } @@ -1380,8 +1390,14 @@ ixl_attach(device_t parent, device_t sel ifmedia_init(&sc->sc_media, IFM_IMASK, ixl_media_change, ixl_media_status); - ixl_media_add(sc, phy_types); + ixl_media_add(sc); ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL); + if (ISSET(sc->sc_phy_abilities, + (IXL_PHY_ABILITY_PAUSE_TX | IXL_PHY_ABILITY_PAUSE_RX))) { + ifmedia_add(&sc->sc_media, + IFM_ETHER | IFM_AUTO | IFM_FLOW, 0, NULL); + } + ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_NONE, 0, NULL); ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO); if_attach(ifp); @@ -1395,6 +1411,8 @@ ixl_attach(device_t parent, device_t sel ixl_config_other_intr(sc); ixl_enable_other_intr(sc); + ixl_set_phy_autoselect(sc); + /* remove default mac filter and replace it so we can see vlans */ rv = ixl_remove_macvlan(sc, sc->sc_enaddr, 0, 0); if (rv != ENOENT) { @@ -1614,21 +1632,41 @@ ixl_vlan_cb(struct ethercom *ec, uint16_ } static void -ixl_media_add(struct ixl_softc *sc, uint64_t phy_types) +ixl_media_add(struct ixl_softc *sc) { struct ifmedia *ifm = &sc->sc_media; const struct ixl_phy_type *itype; unsigned int i; + bool flow; + + if (ISSET(sc->sc_phy_abilities, + (IXL_PHY_ABILITY_PAUSE_TX | IXL_PHY_ABILITY_PAUSE_RX))) { + flow = true; + } else { + flow = false; + } for (i = 0; i < __arraycount(ixl_phy_type_map); i++) { itype = &ixl_phy_type_map[i]; - if (ISSET(phy_types, itype->phy_type)) { + if (ISSET(sc->sc_phy_types, itype->phy_type)) { ifmedia_add(ifm, IFM_ETHER | IFM_FDX | itype->ifm_type, 0, NULL); - if (itype->ifm_type == IFM_100_TX) { - ifmedia_add(ifm, IFM_ETHER | itype->ifm_type, + if (flow) { + ifmedia_add(ifm, + IFM_ETHER | IFM_FDX | IFM_FLOW | + itype->ifm_type, 0, NULL); + } + + if (itype->ifm_type != IFM_100_TX) + continue; + + ifmedia_add(ifm, IFM_ETHER | itype->ifm_type, + 0, NULL); + if (flow) { + ifmedia_add(ifm, + IFM_ETHER | IFM_FLOW | itype->ifm_type, 0, NULL); } } @@ -1652,8 +1690,49 @@ ixl_media_status(struct ifnet *ifp, stru static int ixl_media_change(struct ifnet *ifp) { + struct ixl_softc *sc = ifp->if_softc; + struct ifmedia *ifm = &sc->sc_media; + uint64_t ifm_active = sc->sc_media_active; + uint8_t link_speed, abilities; - return 0; + switch (IFM_SUBTYPE(ifm_active)) { + case IFM_1000_SGMII: + case IFM_1000_KX: + case IFM_10G_KX4: + case IFM_10G_KR: + case IFM_40G_KR4: + case IFM_20G_KR2: + case IFM_25G_KR: + /* backplanes */ + return EINVAL; + } + + abilities = IXL_PHY_ABILITY_AUTONEGO | IXL_PHY_ABILITY_LINKUP; + + switch (IFM_SUBTYPE(ifm->ifm_media)) { + case IFM_AUTO: + link_speed = sc->sc_phy_linkspeed; + break; + case IFM_NONE: + link_speed = 0; + CLR(abilities, IXL_PHY_ABILITY_LINKUP); + break; + default: + link_speed = ixl_search_baudrate( + ifmedia_baudrate(ifm->ifm_media)); + } + + if (ISSET(abilities, IXL_PHY_ABILITY_LINKUP)) { + if (ISSET(link_speed, sc->sc_phy_linkspeed) == 0) + return EINVAL; + } + + if (ifm->ifm_media & IFM_FLOW) { + abilities |= sc->sc_phy_abilities & + (IXL_PHY_ABILITY_PAUSE_TX | IXL_PHY_ABILITY_PAUSE_RX); + } + + return ixl_set_phy_config(sc, link_speed, abilities, false); } static void @@ -4292,11 +4371,10 @@ ixl_get_phy_abilities(struct ixl_softc * } static int -ixl_get_phy_types(struct ixl_softc *sc, uint64_t *phy_types_ptr) +ixl_get_phy_info(struct ixl_softc *sc) { struct ixl_dmamem idm; struct ixl_aq_phy_abilities *phy; - uint64_t phy_types; int rv; if (ixl_dmamem_alloc(sc, &idm, IXL_AQ_BUFLEN, 0) != 0) { @@ -4323,10 +4401,17 @@ ixl_get_phy_types(struct ixl_softc *sc, phy = IXL_DMA_KVA(&idm); - phy_types = le32toh(phy->phy_type); - phy_types |= (uint64_t)le32toh(phy->phy_type_ext) << 32; + sc->sc_phy_types = le32toh(phy->phy_type); + sc->sc_phy_types |= (uint64_t)le32toh(phy->phy_type_ext) << 32; - *phy_types_ptr = phy_types; + sc->sc_phy_abilities = phy->abilities; + sc->sc_phy_linkspeed = phy->link_speed; + sc->sc_phy_fec_cfg = phy->fec_cfg_curr_mod_ext_info & + (IXL_AQ_ENABLE_FEC_KR | IXL_AQ_ENABLE_FEC_RS | + IXL_AQ_REQUEST_FEC_KR | IXL_AQ_REQUEST_FEC_RS); + sc->sc_eee_cap = phy->eee_capability; + sc->sc_eeer_val = phy->eeer_val; + sc->sc_d3_lpan = phy->d3_lpan; rv = 0; @@ -4336,6 +4421,60 @@ done: } static int +ixl_set_phy_config(struct ixl_softc *sc, + uint8_t link_speed, uint8_t abilities, bool polling) +{ + struct ixl_aq_phy_param *param; + struct ixl_atq iatq; + struct ixl_aq_desc *iaq; + int error; + + memset(&iatq, 0, sizeof(iatq)); + + iaq = &iatq.iatq_desc; + iaq->iaq_opcode = htole16(IXL_AQ_OP_PHY_SET_CONFIG); + param = (struct ixl_aq_phy_param *)&iaq->iaq_param; + param->phy_types = htole32((uint32_t)sc->sc_phy_types); + param->phy_type_ext = (uint8_t)(sc->sc_phy_types >> 32); + param->link_speed = link_speed; + param->abilities = abilities | IXL_AQ_PHY_ABILITY_AUTO_LINK; + param->fec_cfg = sc->sc_phy_fec_cfg; + param->eee_capability = sc->sc_eee_cap; + param->eeer_val = sc->sc_eeer_val; + param->d3_lpan = sc->sc_d3_lpan; + + if (polling) + error = ixl_atq_poll(sc, iaq, 250); + else + error = ixl_atq_exec(sc, &iatq); + + if (error != 0) + return error; + + switch (le16toh(iaq->iaq_retval)) { + case IXL_AQ_RC_OK: + break; + case IXL_AQ_RC_EPERM: + return EPERM; + default: + return EIO; + } + + return 0; +} + +static int +ixl_set_phy_autoselect(struct ixl_softc *sc) +{ + uint8_t link_speed, abilities; + + link_speed = sc->sc_phy_linkspeed; + abilities = IXL_PHY_ABILITY_LINKUP | IXL_PHY_ABILITY_AUTONEGO; + + return ixl_set_phy_config(sc, link_speed, abilities, true); +} + +static int ixl_get_link_status_poll(struct ixl_softc *sc) { struct ixl_aq_desc iaq; @@ -4621,6 +4760,23 @@ ixl_search_link_speed(uint8_t link_speed return 0; } +static uint8_t +ixl_search_baudrate(uint64_t baudrate) +{ + const struct ixl_speed_type *type; + unsigned int i; + + for (i = 0; i < __arraycount(ixl_speed_type_map); i++) { + type = &ixl_speed_type_map[i]; + + if (type->net_speed == baudrate) { + return type->dev_speed; + } + } + + return 0; +} + static int ixl_restart_an(struct ixl_softc *sc) { @@ -5397,8 +5553,10 @@ ixl_set_link_status(struct ixl_softc *sc uint64_t baudrate = 0; status = (const struct ixl_aq_link_status *)iaq->iaq_param; - if (!ISSET(status->link_info, IXL_AQ_LINK_UP_FUNCTION)) + if (!ISSET(status->link_info, IXL_AQ_LINK_UP_FUNCTION)) { + ifm_active |= IFM_NONE; goto done; + } ifm_active |= IFM_FDX; ifm_status |= IFM_ACTIVE; Index: src/sys/dev/pci/if_ixlvar.h diff -u src/sys/dev/pci/if_ixlvar.h:1.4 src/sys/dev/pci/if_ixlvar.h:1.5 --- src/sys/dev/pci/if_ixlvar.h:1.4 Fri Jan 17 09:42:05 2020 +++ src/sys/dev/pci/if_ixlvar.h Fri Jan 31 02:16:26 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: if_ixlvar.h,v 1.4 2020/01/17 09:42:05 yamaguchi Exp $ */ +/* $NetBSD: if_ixlvar.h,v 1.5 2020/01/31 02:16:26 yamaguchi Exp $ */ /* * Copyright (c) 2019 Internet Initiative Japan, Inc. @@ -265,6 +265,20 @@ struct ixl_aq_switch_config_element { #define IXL_PHY_TYPE_25GBASE_AOC 0x23 #define IXL_PHY_TYPE_25GBASE_ACC 0x24 +#define IXL_PHY_LINK_SPEED_100MB (1 << 1) +#define IXL_PHY_LINK_SPEED_1000MB (1 << 2) +#define IXL_PHY_LINK_SPEED_10GB (1 << 3) +#define IXL_PHY_LINK_SPEED_40GB (1 << 4) +#define IXL_PHY_LINK_SPEED_20GB (1 << 5) +#define IXL_PHY_LINK_SPEED_25GB (1 << 6) + +#define IXL_PHY_ABILITY_PAUSE_TX (1 << 0) +#define IXL_PHY_ABILITY_PAUSE_RX (1 << 1) +#define IXL_PHY_ABILITY_LOWPOW (1 << 2) +#define IXL_PHY_ABILITY_LINKUP (1 << 3) +#define IXL_PHY_ABILITY_AUTONEGO (1 << 4) +#define IXL_PHY_ABILITY_MODQUAL (1 << 5) + struct ixl_aq_module_desc { uint8_t oui[3]; uint8_t _reserved1; @@ -277,12 +291,6 @@ struct ixl_aq_phy_abilities { uint32_t phy_type; uint8_t link_speed; -#define IXL_AQ_PHY_LINK_SPEED_100MB (1 << 1) -#define IXL_AQ_PHY_LINK_SPEED_1000MB (1 << 2) -#define IXL_AQ_PHY_LINK_SPEED_10GB (1 << 3) -#define IXL_AQ_PHY_LINK_SPEED_40GB (1 << 4) -#define IXL_AQ_PHY_LINK_SPEED_20GB (1 << 5) -#define IXL_AQ_PHY_LINK_SPEED_25GB (1 << 6) uint8_t abilities; uint16_t eee_capability; @@ -317,6 +325,19 @@ struct ixl_aq_phy_abilities { qualified_module[IXL_AQ_PHY_MAX_QMS]; } __packed __aligned(4); +struct ixl_aq_phy_param { + uint32_t phy_types; + uint8_t link_speed; + uint8_t abilities; +#define IXL_AQ_PHY_ABILITY_AUTO_LINK (1 << 5) + uint16_t eee_capability; + uint32_t eeer_val; + uint8_t d3_lpan; + uint8_t phy_type_ext; + uint8_t fec_cfg; + uint8_t config; +} __packed __aligned(4); + struct ixl_aq_link_param { uint8_t notify; #define IXL_AQ_LINK_NOTIFY 0x03