Revise cnmac(4)'s address filter setup
authorvisa <visa@openbsd.org>
Sat, 13 Feb 2021 17:12:38 +0000 (17:12 +0000)
committervisa <visa@openbsd.org>
Sat, 13 Feb 2021 17:12:38 +0000 (17:12 +0000)
Set up the DMAC filter in one go instead of doing it separately for
unicast and multicast DMACs. This attempts to make the code a little
more readable. The setup should now run a bit faster as well because
it now does fewer register accesses.

Tested on CN5020, CN6120 and CN7130.

sys/arch/octeon/dev/cn30xxgmx.c
sys/arch/octeon/dev/cn30xxgmxreg.h
sys/arch/octeon/dev/cn30xxgmxvar.h
sys/arch/octeon/dev/if_cnmac.c

index f27b180..9b601c9 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: cn30xxgmx.c,v 1.49 2021/02/04 16:16:10 visa Exp $     */
+/*     $OpenBSD: cn30xxgmx.c,v 1.50 2021/02/13 17:12:38 visa Exp $     */
 
 /*
  * Copyright (c) 2007 Internet Initiative Japan, Inc.
 #include <octeon/dev/cn30xxpipvar.h>
 #include <octeon/dev/cn30xxsmivar.h>
 
-#define        dprintf(...)
-#define        OCTEON_ETH_KASSERT      KASSERT
-
-#define        ADDR2UINT64(u, a) \
-       do { \
-               u = \
-                   (((uint64_t)a[0] << 40) | ((uint64_t)a[1] << 32) | \
-                    ((uint64_t)a[2] << 24) | ((uint64_t)a[3] << 16) | \
-                    ((uint64_t)a[4] <<  8) | ((uint64_t)a[5] <<  0)); \
-       } while (0)
-#define        UINT642ADDR(a, u) \
-       do { \
-               a[0] = (uint8_t)((u) >> 40); a[1] = (uint8_t)((u) >> 32); \
-               a[2] = (uint8_t)((u) >> 24); a[3] = (uint8_t)((u) >> 16); \
-               a[4] = (uint8_t)((u) >>  8); a[5] = (uint8_t)((u) >>  0); \
-       } while (0)
+#define GMX_NCAM       8
 
 #define        _GMX_RD8(sc, off) \
        bus_space_read_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_gmx->sc_regh, (off))
@@ -127,11 +112,6 @@ int        cn30xxgmx_rgmii_speed_newlink_log(struct cn30xxgmx_port_softc *,
            uint64_t);
 #endif
 
-static const int       cn30xxgmx_rx_adr_cam_regs[] = {
-       GMX0_RX0_ADR_CAM0, GMX0_RX0_ADR_CAM1, GMX0_RX0_ADR_CAM2,
-       GMX0_RX0_ADR_CAM3, GMX0_RX0_ADR_CAM4, GMX0_RX0_ADR_CAM5
-};
-
 struct cn30xxgmx_port_ops cn30xxgmx_port_ops_agl = {
        .port_ops_enable = cn30xxgmx_agl_enable,
        .port_ops_speed = cn30xxgmx_agl_speed,
@@ -642,26 +622,6 @@ cn30xxgmx_tx_thresh(struct cn30xxgmx_port_softc *sc, int cnt)
        return 0;
 }
 
-int
-cn30xxgmx_set_mac_addr(struct cn30xxgmx_port_softc *sc, uint8_t *addr)
-{
-       uint64_t mac;
-       int i;
-
-       ADDR2UINT64(mac, addr);
-
-       cn30xxgmx_link_enable(sc, 0);
-
-       sc->sc_mac = mac;
-       _GMX_PORT_WR8(sc, GMX0_SMAC0, mac);
-       for (i = 0; i < 6; i++)
-               _GMX_PORT_WR8(sc, cn30xxgmx_rx_adr_cam_regs[i], addr[i]);
-
-       cn30xxgmx_link_enable(sc, 1);
-
-       return 0;
-}
-
 int
 cn30xxgmx_set_filter(struct cn30xxgmx_port_softc *sc)
 {
@@ -669,16 +629,11 @@ cn30xxgmx_set_filter(struct cn30xxgmx_port_softc *sc)
        struct arpcom *ac = sc->sc_port_ac;
        struct ether_multi *enm;
        struct ether_multistep step;
-       uint64_t cam_en = 0x01ULL;
+       uint64_t cam[ETHER_ADDR_LEN];
+       uint64_t cam_en = 0;
        uint64_t ctl = 0;
-       int multi = 0;
-
-       cn30xxgmx_link_enable(sc, 0);
-
-       SET(ctl, RXN_ADR_CTL_CAM_MODE);
-       CLR(ctl, RXN_ADR_CTL_MCST_ACCEPT | RXN_ADR_CTL_MCST_AFCAM |
-           RXN_ADR_CTL_MCST_REJECT);
-       CLR(ifp->if_flags, IFF_ALLMULTI);
+       uint64_t mac;
+       int i, cidx;
 
        /*
         * Always accept broadcast frames.
@@ -687,63 +642,53 @@ cn30xxgmx_set_filter(struct cn30xxgmx_port_softc *sc)
 
        if (ISSET(ifp->if_flags, IFF_PROMISC)) {
                SET(ifp->if_flags, IFF_ALLMULTI);
-               CLR(ctl, RXN_ADR_CTL_CAM_MODE);
                SET(ctl, RXN_ADR_CTL_MCST_ACCEPT);
-               cam_en = 0x00ULL;
-       } else if (ac->ac_multirangecnt > 0 || ac->ac_multicnt > 7) {
+       } else if (ac->ac_multirangecnt > 0 || ac->ac_multicnt >= GMX_NCAM) {
                SET(ifp->if_flags, IFF_ALLMULTI);
+               SET(ctl, RXN_ADR_CTL_CAM_MODE);
                SET(ctl, RXN_ADR_CTL_MCST_ACCEPT);
        } else {
-               /*
-                * Note first entry is self MAC address; other 7 entires are
-                * available for multicast addresses.
-                */
-               ETHER_FIRST_MULTI(step, sc->sc_port_ac, enm);
-               while (enm != NULL) {
-                       int i;
-
-                       dprintf("%d: %02x:%02x:%02x:%02x:%02x:%02x\n"
-                           multi + 1,
-                           enm->enm_addrlo[0], enm->enm_addrlo[1],
-                           enm->enm_addrlo[2], enm->enm_addrlo[3],
-                           enm->enm_addrlo[4], enm->enm_addrlo[5]);
-                       multi++;
-
-                       SET(cam_en, 1ULL << multi); /* XXX */
-
-                       for (i = 0; i < 6; i++) {
-                               uint64_t tmp;
-
-                               /* XXX */
-                               tmp = _GMX_PORT_RD8(sc,
-                                   cn30xxgmx_rx_adr_cam_regs[i]);
-                               CLR(tmp, 0xffULL << (8 * multi));
-                               SET(tmp, (uint64_t)enm->enm_addrlo[i] <<
-                                   (8 * multi));
-                               _GMX_PORT_WR8(sc, cn30xxgmx_rx_adr_cam_regs[i],
-                                   tmp);
-                       }
+               CLR(ifp->if_flags, IFF_ALLMULTI);
+               SET(ctl, RXN_ADR_CTL_CAM_MODE);
+               SET(ctl, RXN_ADR_CTL_MCST_AFCAM);
+       }
 
-                       for (i = 0; i < 6; i++)
-                               dprintf("cam%d = %016llx\n", i,
-                                   _GMX_PORT_RD8(sc,
-                                   cn30xxgmx_rx_adr_cam_regs[i]));
+       mac = 0;
+       for (i = 0; i < ETHER_ADDR_LEN; i++)
+               mac |= (uint64_t)ac->ac_enaddr[i] <<
+                   ((ETHER_ADDR_LEN - 1 - i) * 8);
 
+       /*
+        * The first CAM entry is used for the local unicast MAC.
+        * The remaining entries are used for multicast MACs.
+        */
+       memset(cam, 0, sizeof(cam));
+       cidx = 0;
+       if (!ISSET(ifp->if_flags, IFF_PROMISC)) {
+               for (i = 0; i < ETHER_ADDR_LEN; i++)
+                       cam[i] |= (uint64_t)ac->ac_enaddr[i] << (cidx * 8);
+               cam_en |= 1U << cidx;
+               cidx++;
+       }
+       if (!ISSET(ifp->if_flags, IFF_ALLMULTI)) {
+               ETHER_FIRST_MULTI(step, ac, enm);
+               while (enm != NULL && cidx < GMX_NCAM) {
+                       for (i = 0; i < ETHER_ADDR_LEN; i++)
+                               cam[i] |= (uint64_t)enm->enm_addrlo[i] <<
+                                   (cidx * 8);
+                       cam_en |= 1U << cidx;
+                       cidx++;
                        ETHER_NEXT_MULTI(step, enm);
                }
-
-               if (multi)
-                       SET(ctl, RXN_ADR_CTL_MCST_AFCAM);
-               else
-                       SET(ctl, RXN_ADR_CTL_MCST_REJECT);
-
-               OCTEON_ETH_KASSERT(enm == NULL);
        }
 
-       dprintf("ctl = %llx, cam_en = %llx\n", ctl, cam_en);
+       cn30xxgmx_link_enable(sc, 0);
+       _GMX_PORT_WR8(sc, GMX0_SMAC0, mac);
        _GMX_PORT_WR8(sc, GMX0_RX0_ADR_CTL, ctl);
+       for (i = 0; i < ETHER_ADDR_LEN; i++)
+               _GMX_PORT_WR8(sc, GMX0_RX0_ADR_CAM(i), cam[i]);
        _GMX_PORT_WR8(sc, GMX0_RX0_ADR_CAM_EN, cam_en);
-
+       (void)_GMX_PORT_RD8(sc, GMX0_RX0_ADR_CAM_EN);
        cn30xxgmx_link_enable(sc, 1);
 
        return 0;
index c601a40..55edb36 100644 (file)
@@ -3,7 +3,7 @@
  * DONT EDIT THIS FILE
  */
 
-/*     $OpenBSD: cn30xxgmxreg.h,v 1.7 2020/09/08 13:54:48 visa Exp $   */
+/*     $OpenBSD: cn30xxgmxreg.h,v 1.8 2021/02/13 17:12:38 visa Exp $   */
 
 /*
  * Copyright (c) 2007 Internet Initiative Japan, Inc.
 #define        GMX0_RX0_STATS_PKTS_BAD                 0x0c0
 #define        GMX0_RX0_ADR_CTL                        0x100
 #define        GMX0_RX0_ADR_CAM_EN                     0x108
-#define        GMX0_RX0_ADR_CAM0                       0x180
-#define        GMX0_RX0_ADR_CAM1                       0x188
-#define        GMX0_RX0_ADR_CAM2                       0x190
-#define        GMX0_RX0_ADR_CAM3                       0x198
-#define        GMX0_RX0_ADR_CAM4                       0x1a0
-#define        GMX0_RX0_ADR_CAM5                       0x1a8
+#define        GMX0_RX0_ADR_CAM(i)                     (0x180 + (i) * 8)
 #define        GMX0_TX0_CLK                            0x208
 #define        GMX0_TX0_THRESH                         0x210
 #define        GMX0_TX0_APPEND                         0x218
index 066ba8b..1368b5b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: cn30xxgmxvar.h,v 1.11 2020/09/08 13:54:48 visa Exp $  */
+/*     $OpenBSD: cn30xxgmxvar.h,v 1.12 2021/02/13 17:12:38 visa Exp $  */
 
 /*
  * Copyright (c) 2007 Internet Initiative Japan, Inc.
@@ -61,7 +61,6 @@ struct cn30xxgmx_port_softc {
        bus_space_handle_t      sc_port_regh;
        int                     sc_port_no;     /* GMX0:0, GMX0:1, ... */
        int                     sc_port_type;
-       uint64_t                sc_mac;
        uint64_t                sc_link;
        struct mii_data         *sc_port_mii;
        struct arpcom           *sc_port_ac;
@@ -111,7 +110,6 @@ int         cn30xxgmx_rx_frm_ctl_enable(struct cn30xxgmx_port_softc *,
 int            cn30xxgmx_rx_frm_ctl_disable(struct cn30xxgmx_port_softc *,
                    uint64_t rx_frm_ctl);
 int            cn30xxgmx_tx_thresh(struct cn30xxgmx_port_softc *, int);
-int            cn30xxgmx_set_mac_addr(struct cn30xxgmx_port_softc *, uint8_t *);
 int            cn30xxgmx_set_filter(struct cn30xxgmx_port_softc *);
 int            cn30xxgmx_port_enable(struct cn30xxgmx_port_softc *, int);
 int            cn30xxgmx_reset_speed(struct cn30xxgmx_port_softc *);
index c3f20ff..ebb341f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_cnmac.c,v 1.80 2020/12/12 11:48:52 jan Exp $       */
+/*     $OpenBSD: if_cnmac.c,v 1.81 2021/02/13 17:12:38 visa Exp $      */
 
 /*
  * Copyright (c) 2007 Internet Initiative Japan, Inc.
@@ -247,7 +247,6 @@ cnmac_attach(struct device *parent, struct device *self, void *aux)
        struct cnmac_softc *sc = (void *)self;
        struct cn30xxgmx_attach_args *ga = aux;
        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
-       uint8_t enaddr[ETHER_ADDR_LEN];
 
        if (cnmac_npowgroups >= OCTEON_POW_GROUP_MAX) {
                printf(": out of POW groups\n");
@@ -275,8 +274,8 @@ cnmac_attach(struct device *parent, struct device *self, void *aux)
         */
        sc->sc_ip_offset = 0/* XXX */;
 
-       cnmac_board_mac_addr(enaddr);
-       printf(", address %s\n", ether_sprintf(enaddr));
+       cnmac_board_mac_addr(sc->sc_arpcom.ac_enaddr);
+       printf(", address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
 
        ml_init(&sc->sc_sendq);
        sc->sc_soft_req_thresh = 15/* XXX */;
@@ -319,12 +318,9 @@ cnmac_attach(struct device *parent, struct device *self, void *aux)
        ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_CSUM_TCPv4 |
            IFCAP_CSUM_UDPv4 | IFCAP_CSUM_TCPv6 | IFCAP_CSUM_UDPv6;
 
-       cn30xxgmx_set_mac_addr(sc->sc_gmx_port, enaddr);
        cn30xxgmx_set_filter(sc->sc_gmx_port);
 
        if_attach(ifp);
-
-       memcpy(sc->sc_arpcom.ac_enaddr, enaddr, ETHER_ADDR_LEN);
        ether_ifattach(ifp);
 
        cnmac_buf_init(sc);
@@ -1011,7 +1007,6 @@ cnmac_init(struct ifnet *ifp)
 
        cn30xxpip_stats_init(sc->sc_pip);
        cn30xxgmx_stats_init(sc->sc_gmx_port);
-       cn30xxgmx_set_mac_addr(sc->sc_gmx_port, sc->sc_arpcom.ac_enaddr);
        cn30xxgmx_set_filter(sc->sc_gmx_port);
 
        timeout_add_sec(&sc->sc_tick_misc_ch, 1);