Module Name:    src
Committed By:   yamaguchi
Date:           Fri Dec 20 02:19:27 UTC 2019

Modified Files:
        src/sys/dev/pci: if_ixl.c

Log Message:
ixl(4) supports ETHERCAP_VLAN_HWFILTER
the feature is disable by default.

reviewed by msaitoh and knakahara


To generate a diff of this commit:
cvs rdiff -u -r1.11 -r1.12 src/sys/dev/pci/if_ixl.c

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.11 src/sys/dev/pci/if_ixl.c:1.12
--- src/sys/dev/pci/if_ixl.c:1.11	Fri Dec 20 02:12:31 2019
+++ src/sys/dev/pci/if_ixl.c	Fri Dec 20 02:19:27 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_ixl.c,v 1.11 2019/12/20 02:12:31 yamaguchi Exp $	*/
+/*	$NetBSD: if_ixl.c,v 1.12 2019/12/20 02:19:27 yamaguchi Exp $	*/
 
 /*
  * Copyright (c) 2013-2015, Intel Corporation
@@ -646,8 +646,8 @@ static int	ixl_set_link_status(struct ix
 static void	ixl_config_rss(struct ixl_softc *);
 static int	ixl_add_macvlan(struct ixl_softc *, const uint8_t *,
 		    uint16_t, uint16_t);
-static int	ixl_remove_macvlan(struct ixl_softc *, uint8_t *, uint16_t,
-		    uint16_t);
+static int	ixl_remove_macvlan(struct ixl_softc *, const uint8_t *,
+		    uint16_t, uint16_t);
 static void	ixl_arq(void *);
 static void	ixl_hmc_pack(void *, const void *,
 		    const struct ixl_hmc_pack *, unsigned int);
@@ -725,7 +725,10 @@ static const struct ixl_product *
 		ixl_lookup(const struct pci_attach_args *pa);
 static void	ixl_link_state_update(struct ixl_softc *,
 		    const struct ixl_aq_desc *);
-static int	ixl_set_macvlan(struct ixl_softc *);
+static int	ixl_vlan_cb(struct ethercom *, uint16_t, bool);
+static int	ixl_setup_vlan_hwfilter(struct ixl_softc *);
+static void	ixl_teardown_vlan_hwfilter(struct ixl_softc *);
+static int	ixl_update_macvlan(struct ixl_softc *);
 static int	ixl_setup_interrupts(struct ixl_softc *);;
 static void	ixl_teardown_interrupts(struct ixl_softc *);
 static int	ixl_setup_stats(struct ixl_softc *);
@@ -1194,10 +1197,15 @@ ixl_attach(device_t parent, device_t sel
 	    IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx |
 	    IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx;
 #endif
+	ether_set_vlan_cb(&sc->sc_ec, ixl_vlan_cb);
 	sc->sc_ec.ec_capabilities |= ETHERCAP_VLAN_MTU;
 	sc->sc_ec.ec_capabilities |= ETHERCAP_VLAN_HWTAGGING;
+	sc->sc_ec.ec_capabilities |= ETHERCAP_VLAN_HWFILTER;
 
 	sc->sc_ec.ec_capenable = sc->sc_ec.ec_capabilities;
+	/* Disable VLAN_HWFILTER by default */
+	CLR(sc->sc_ec.ec_capenable, ETHERCAP_VLAN_HWFILTER);
+
 	sc->sc_cur_ec_capenable = sc->sc_ec.ec_capenable;
 
 	sc->sc_ec.ec_ifmedia = &sc->sc_media;
@@ -1219,7 +1227,25 @@ ixl_attach(device_t parent, device_t sel
 	ixl_config_other_intr(sc);
 	ixl_enable_other_intr(sc);
 
-	ixl_set_macvlan(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) {
+		aprint_debug_dev(self,
+		    "unable to remove macvlan %u\n", rv);
+	}
+	rv = ixl_remove_macvlan(sc, sc->sc_enaddr, 0,
+	    IXL_AQ_OP_REMOVE_MACVLAN_IGNORE_VLAN);
+	if (rv != ENOENT) {
+		aprint_debug_dev(self,
+		    "unable to remove macvlan, ignore vlan %u\n", rv);
+	}
+
+	if (ixl_update_macvlan(sc) != 0) {
+		aprint_debug_dev(self,
+		    "couldn't enable vlan hardware filter\n");
+		CLR(sc->sc_ec.ec_capenable, ETHERCAP_VLAN_HWFILTER);
+		CLR(sc->sc_cur_ec_capenable, ETHERCAP_VLAN_HWFILTER);
+	}
 
 	sc->sc_txrx_workqueue = true;
 	sc->sc_tx_process_limit = IXL_TX_PROCESS_LIMIT;
@@ -1380,6 +1406,34 @@ ixl_workqs_teardown(device_t self)
 	return 0;
 }
 
+static int
+ixl_vlan_cb(struct ethercom *ec, uint16_t vid, bool set)
+{
+	struct ifnet *ifp = &ec->ec_if;
+	struct ixl_softc *sc = ifp->if_softc;
+	int rv;
+
+	if (!ISSET(sc->sc_cur_ec_capenable, ETHERCAP_VLAN_HWFILTER)) {
+		return 0;
+	}
+
+	if (set) {
+		rv = ixl_add_macvlan(sc, sc->sc_enaddr, vid,
+		    IXL_AQ_OP_ADD_MACVLAN_PERFECT_MATCH);
+		if (rv == 0) {
+			rv = ixl_add_macvlan(sc, etherbroadcastaddr,
+			    vid, IXL_AQ_OP_ADD_MACVLAN_PERFECT_MATCH);
+		}
+	} else {
+		rv = ixl_remove_macvlan(sc, sc->sc_enaddr, vid,
+		    IXL_AQ_OP_REMOVE_MACVLAN_PERFECT_MATCH);
+		(void)ixl_remove_macvlan(sc, etherbroadcastaddr, vid,
+		    IXL_AQ_OP_REMOVE_MACVLAN_PERFECT_MATCH);
+	}
+
+	return rv;
+}
+
 static void
 ixl_media_add(struct ixl_softc *sc, uint64_t phy_types)
 {
@@ -1460,6 +1514,7 @@ ixl_add_multi(struct ixl_softc *sc, uint
 		return ENETRESET;
 	}
 
+	/* multicast address can not use VLAN HWFILTER */
 	rv = ixl_add_macvlan(sc, addrlo, 0,
 	    IXL_AQ_OP_ADD_MACVLAN_IGNORE_VLAN);
 
@@ -1726,7 +1781,6 @@ ixl_reinit(struct ixl_softc *sc)
 	if (ixl_set_vsi(sc) != 0)
 		return EIO;
 
-
 	for (i = 0; i < sc->sc_nqueue_pairs; i++) {
 		txr = sc->sc_qps[i].qp_txr;
 		rxr = sc->sc_qps[i].qp_rxr;
@@ -1752,7 +1806,6 @@ ixl_reinit(struct ixl_softc *sc)
 		ixl_wr(sc, txr->txr_tail, txr->txr_prod);
 		ixl_wr(sc, rxr->rxr_tail, rxr->rxr_prod);
 
-
 		/* ixl_rxfill() needs lock held */
 		mutex_enter(&rxr->rxr_lock);
 		ixl_rxfill(sc, rxr);
@@ -1791,7 +1844,7 @@ ixl_init_locked(struct ixl_softc *sc)
 {
 	struct ifnet *ifp = &sc->sc_ec.ec_if;
 	unsigned int i;
-	int error;
+	int error, eccap_change;
 
 	KASSERT(mutex_owned(&sc->sc_cfg_lock));
 
@@ -1802,7 +1855,18 @@ ixl_init_locked(struct ixl_softc *sc)
 		return ENXIO;
 	}
 
-	sc->sc_cur_ec_capenable = sc->sc_ec.ec_capenable;
+	eccap_change = sc->sc_ec.ec_capenable ^ sc->sc_cur_ec_capenable;
+	if (ISSET(eccap_change, ETHERCAP_VLAN_HWTAGGING))
+		sc->sc_cur_ec_capenable ^= ETHERCAP_VLAN_HWTAGGING;
+
+	if (ISSET(eccap_change, ETHERCAP_VLAN_HWFILTER)) {
+		if (ixl_update_macvlan(sc) == 0) {
+			sc->sc_cur_ec_capenable ^= ETHERCAP_VLAN_HWFILTER;
+		} else {
+			CLR(sc->sc_ec.ec_capenable, ETHERCAP_VLAN_HWFILTER);
+			CLR(sc->sc_cur_ec_capenable, ETHERCAP_VLAN_HWFILTER);
+		}
+	}
 
 	if (sc->sc_intrtype != PCI_INTR_TYPE_MSIX)
 		sc->sc_nqueue_pairs = 1;
@@ -1856,6 +1920,7 @@ ixl_iff(struct ixl_softc *sc)
 	struct ixl_atq iatq;
 	struct ixl_aq_desc *iaq;
 	struct ixl_aq_vsi_promisc_param *param;
+	uint16_t flag_add, flag_del;
 	int error;
 
 	if (!ISSET(ifp->if_flags, IFF_RUNNING))
@@ -1867,8 +1932,14 @@ ixl_iff(struct ixl_softc *sc)
 	iaq->iaq_opcode = htole16(IXL_AQ_OP_SET_VSI_PROMISC);
 
 	param = (struct ixl_aq_vsi_promisc_param *)&iaq->iaq_param;
-	param->flags = htole16(IXL_AQ_VSI_PROMISC_FLAG_BCAST |
-	    IXL_AQ_VSI_PROMISC_FLAG_VLAN);
+	param->flags = htole16(0);
+
+	if (!ISSET(sc->sc_cur_ec_capenable, ETHERCAP_VLAN_HWFILTER)
+	    || ISSET(ifp->if_flags, IFF_PROMISC)) {
+		param->flags |= htole16(IXL_AQ_VSI_PROMISC_FLAG_BCAST |
+		    IXL_AQ_VSI_PROMISC_FLAG_VLAN);
+	}
+
 	if (ISSET(ifp->if_flags, IFF_PROMISC)) {
 		param->flags |= htole16(IXL_AQ_VSI_PROMISC_FLAG_UCAST |
 		    IXL_AQ_VSI_PROMISC_FLAG_MCAST);
@@ -1888,12 +1959,18 @@ ixl_iff(struct ixl_softc *sc)
 		return EIO;
 
 	if (memcmp(sc->sc_enaddr, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN) != 0) {
-		ixl_remove_macvlan(sc, sc->sc_enaddr, 0,
-		    IXL_AQ_OP_REMOVE_MACVLAN_IGNORE_VLAN);
+		if (ISSET(sc->sc_cur_ec_capenable, ETHERCAP_VLAN_HWFILTER)) {
+			flag_add = IXL_AQ_OP_ADD_MACVLAN_PERFECT_MATCH;
+			flag_del = IXL_AQ_OP_REMOVE_MACVLAN_PERFECT_MATCH;
+		} else {
+			flag_add = IXL_AQ_OP_ADD_MACVLAN_IGNORE_VLAN;
+			flag_del = IXL_AQ_OP_REMOVE_MACVLAN_IGNORE_VLAN;
+		}
+
+		ixl_remove_macvlan(sc, sc->sc_enaddr, 0, flag_del);
 
 		memcpy(sc->sc_enaddr, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN);
-		ixl_add_macvlan(sc, sc->sc_enaddr, 0,
-		    IXL_AQ_OP_ADD_MACVLAN_IGNORE_VLAN);
+		ixl_add_macvlan(sc, sc->sc_enaddr, 0, flag_add);
 	}
 	return 0;
 }
@@ -3959,7 +4036,14 @@ ixl_get_vsi(struct ixl_softc *sc)
 		return ETIMEDOUT;
 	}
 
-	if (iaq.iaq_retval != htole16(IXL_AQ_RC_OK)) {
+	switch (le16toh(iaq.iaq_retval)) {
+	case IXL_AQ_RC_OK:
+		break;
+	case IXL_AQ_RC_ENOENT:
+		return ENOENT;
+	case IXL_AQ_RC_EACCES:
+		return EACCES;
+	default:
 		return EIO;
 	}
 
@@ -4027,7 +4111,14 @@ ixl_set_vsi(struct ixl_softc *sc)
 		return ETIMEDOUT;
 	}
 
-	if (iaq.iaq_retval != htole16(IXL_AQ_RC_OK)) {
+	switch (le16toh(iaq.iaq_retval)) {
+	case IXL_AQ_RC_OK:
+		break;
+	case IXL_AQ_RC_ENOENT:
+		return ENOENT;
+	case IXL_AQ_RC_EACCES:
+		return EACCES;
+	default:
 		return EIO;
 	}
 
@@ -4243,7 +4334,7 @@ ixl_add_macvlan(struct ixl_softc *sc, co
 }
 
 static int
-ixl_remove_macvlan(struct ixl_softc *sc, uint8_t *macaddr,
+ixl_remove_macvlan(struct ixl_softc *sc, const uint8_t *macaddr,
     uint16_t vlan, uint16_t flags)
 {
 	struct ixl_aq_desc iaq;
@@ -4821,39 +4912,80 @@ ixl_dmamem_free(struct ixl_softc *sc, st
 }
 
 static int
-ixl_set_macvlan(struct ixl_softc *sc)
+ixl_setup_vlan_hwfilter(struct ixl_softc *sc)
 {
-	int	 error, rv = 0;
+	struct ethercom *ec = &sc->sc_ec;
+	struct vlanid_list *vlanidp;
+	int rv;
 
-	/* remove default mac filter and replace it so we can see vlans */
+	ixl_remove_macvlan(sc, sc->sc_enaddr, 0,
+	    IXL_AQ_OP_REMOVE_MACVLAN_IGNORE_VLAN);
+	ixl_remove_macvlan(sc, etherbroadcastaddr, 0,
+	    IXL_AQ_OP_REMOVE_MACVLAN_IGNORE_VLAN);
 
-	error = ixl_remove_macvlan(sc, sc->sc_enaddr, 0, 0);
-	if (error != 0 && error != ENOENT) {
-		aprint_debug_dev(sc->sc_dev, "unable to remove macvlan\n");
-		rv = -1;
-	}
+	rv = ixl_add_macvlan(sc, sc->sc_enaddr, 0,
+	    IXL_AQ_OP_ADD_MACVLAN_PERFECT_MATCH);
+	if (rv != 0)
+		return rv;
+	rv = ixl_add_macvlan(sc, etherbroadcastaddr, 0,
+	    IXL_AQ_OP_ADD_MACVLAN_PERFECT_MATCH);
+	if (rv != 0)
+		return rv;
 
-	error = ixl_remove_macvlan(sc, sc->sc_enaddr, 0,
-	    IXL_AQ_OP_REMOVE_MACVLAN_IGNORE_VLAN);
-	if (error != 0 && error != ENOENT) {
-		aprint_debug_dev(sc->sc_dev,
-		    "unable to remove macvlan(IGNORE_VLAN)\n");
-		rv = -1;
+	ETHER_LOCK(ec);
+	SIMPLEQ_FOREACH(vlanidp, &ec->ec_vids, vid_list) {
+		rv = ixl_add_macvlan(sc, sc->sc_enaddr,
+		    vlanidp->vid, IXL_AQ_OP_ADD_MACVLAN_PERFECT_MATCH);
+		if (rv != 0)
+			break;
+		rv = ixl_add_macvlan(sc, etherbroadcastaddr,
+		    vlanidp->vid, IXL_AQ_OP_ADD_MACVLAN_PERFECT_MATCH);
+		if (rv != 0)
+			break;
 	}
+	ETHER_UNLOCK(ec);
 
-	error = ixl_add_macvlan(sc, sc->sc_enaddr, 0,
-	    IXL_AQ_OP_ADD_MACVLAN_IGNORE_VLAN);
-	if (error != 0) {
-		aprint_debug_dev(sc->sc_dev, "unable to add mac address\n");
-		rv = -1;
+	return rv;
+}
+
+static void
+ixl_teardown_vlan_hwfilter(struct ixl_softc *sc)
+{
+	struct vlanid_list *vlanidp;
+	struct ethercom *ec = &sc->sc_ec;
+
+	ixl_remove_macvlan(sc, sc->sc_enaddr, 0,
+	    IXL_AQ_OP_REMOVE_MACVLAN_PERFECT_MATCH);
+	ixl_remove_macvlan(sc, etherbroadcastaddr, 0,
+	    IXL_AQ_OP_REMOVE_MACVLAN_PERFECT_MATCH);
+
+	ETHER_LOCK(ec);
+	SIMPLEQ_FOREACH(vlanidp, &ec->ec_vids, vid_list) {
+		ixl_remove_macvlan(sc, sc->sc_enaddr,
+		    vlanidp->vid, IXL_AQ_OP_REMOVE_MACVLAN_PERFECT_MATCH);
+		ixl_remove_macvlan(sc, etherbroadcastaddr,
+		    vlanidp->vid, IXL_AQ_OP_REMOVE_MACVLAN_PERFECT_MATCH);
 	}
+	ETHER_UNLOCK(ec);
 
-	error = ixl_add_macvlan(sc, etherbroadcastaddr, 0,
+	ixl_add_macvlan(sc, sc->sc_enaddr, 0,
 	    IXL_AQ_OP_ADD_MACVLAN_IGNORE_VLAN);
-	if (error != 0) {
-		aprint_debug_dev(sc->sc_dev,
-		    "unable to add broadcast mac address\n");
-		rv = -1;
+	ixl_add_macvlan(sc, etherbroadcastaddr, 0,
+	    IXL_AQ_OP_ADD_MACVLAN_IGNORE_VLAN);
+}
+
+static int
+ixl_update_macvlan(struct ixl_softc *sc)
+{
+	int rv = 0;
+	int next_ec_capenable = sc->sc_ec.ec_capenable;
+
+	if (ISSET(next_ec_capenable, ETHERCAP_VLAN_HWFILTER)) {
+		rv = ixl_setup_vlan_hwfilter(sc);
+		if (rv != 0)
+			ixl_teardown_vlan_hwfilter(sc);
+	} else {
+		ixl_teardown_vlan_hwfilter(sc);
 	}
 
 	return rv;
@@ -4871,10 +5003,21 @@ ixl_ifflags_cb(struct ethercom *ec)
 	change = ec->ec_capenable ^ sc->sc_cur_ec_capenable;
 
 	if (ISSET(change, ETHERCAP_VLAN_HWTAGGING)) {
+		sc->sc_cur_ec_capenable ^= ETHERCAP_VLAN_HWTAGGING;
 		rv = ENETRESET;
 		goto out;
 	}
 
+	if (ISSET(change, ETHERCAP_VLAN_HWFILTER)) {
+		rv = ixl_update_macvlan(sc);
+		if (rv == 0) {
+			sc->sc_cur_ec_capenable ^= ETHERCAP_VLAN_HWFILTER;
+		} else {
+			CLR(ec->ec_capenable, ETHERCAP_VLAN_HWFILTER);
+			CLR(sc->sc_cur_ec_capenable, ETHERCAP_VLAN_HWFILTER);
+		}
+	}
+
 	rv = ixl_iff(sc);
 out:
 	mutex_exit(&sc->sc_cfg_lock);
@@ -5496,8 +5639,6 @@ ixl_rx_ctl_read(struct ixl_softc *sc, ui
 	return 0;
 }
 
-
-
 static uint32_t
 ixl_rd_rx_csr(struct ixl_softc *sc, uint32_t reg)
 {

Reply via email to