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

Reply via email to