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