Module Name:    src
Committed By:   simonb
Date:           Tue Jun 23 05:17:13 UTC 2020

Modified Files:
        src/sys/arch/mips/cavium/dev: if_cnmac.c if_cnmacvar.h octeon_gmx.c
            octeon_gmxreg.h octeon_gmxvar.h

Log Message:
Redo cnmac attachments - cnmacM @ gmxN @ pip0 @ iobus
Support SGMII mode used on CN70XX.
Most functional changes from OpenBSD octeon port.  Still more to come from
the OpenBSD driver.


To generate a diff of this commit:
cvs rdiff -u -r1.23 -r1.24 src/sys/arch/mips/cavium/dev/if_cnmac.c
cvs rdiff -u -r1.3 -r1.4 src/sys/arch/mips/cavium/dev/if_cnmacvar.h
cvs rdiff -u -r1.14 -r1.15 src/sys/arch/mips/cavium/dev/octeon_gmx.c
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/mips/cavium/dev/octeon_gmxreg.h
cvs rdiff -u -r1.6 -r1.7 src/sys/arch/mips/cavium/dev/octeon_gmxvar.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/arch/mips/cavium/dev/if_cnmac.c
diff -u src/sys/arch/mips/cavium/dev/if_cnmac.c:1.23 src/sys/arch/mips/cavium/dev/if_cnmac.c:1.24
--- src/sys/arch/mips/cavium/dev/if_cnmac.c:1.23	Mon Jun 22 02:26:19 2020
+++ src/sys/arch/mips/cavium/dev/if_cnmac.c	Tue Jun 23 05:17:13 2020
@@ -1,11 +1,33 @@
-/*	$NetBSD: if_cnmac.c,v 1.23 2020/06/22 02:26:19 simonb Exp $	*/
+/*	$NetBSD: if_cnmac.c,v 1.24 2020/06/23 05:17:13 simonb Exp $	*/
 
-#include <sys/cdefs.h>
-#if 0
-__KERNEL_RCSID(0, "$NetBSD: if_cnmac.c,v 1.23 2020/06/22 02:26:19 simonb Exp $");
-#endif
+/*
+ * Copyright (c) 2007 Internet Initiative Japan, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
 
-#include "opt_octeon.h"
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: if_cnmac.c,v 1.24 2020/06/23 05:17:13 simonb Exp $");
 
 /*
  * If no free send buffer is available, free all the sent buffers and bail out.
@@ -30,7 +52,6 @@ __KERNEL_RCSID(0, "$NetBSD: if_cnmac.c,v
 #include <sys/syslog.h>
 
 #include <net/if.h>
-#include <net/if_dl.h>
 #include <net/if_media.h>
 #include <net/if_ether.h>
 #include <net/route.h>
@@ -52,23 +73,24 @@ __KERNEL_RCSID(0, "$NetBSD: if_cnmac.c,v
 #include <mips/cpuregs.h>
 
 #include <mips/cavium/octeonreg.h>
+#include <mips/cavium/octeonvar.h>
 #include <mips/cavium/include/iobusvar.h>
 
 #include <mips/cavium/dev/octeon_ciureg.h>
+#include <mips/cavium/dev/octeon_faureg.h>
+#include <mips/cavium/dev/octeon_fpareg.h>
 #include <mips/cavium/dev/octeon_gmxreg.h>
 #include <mips/cavium/dev/octeon_pipreg.h>
 #include <mips/cavium/dev/octeon_powreg.h>
-#include <mips/cavium/dev/octeon_faureg.h>
-#include <mips/cavium/dev/octeon_fpareg.h>
+#include <mips/cavium/dev/octeon_fauvar.h>
 #include <mips/cavium/dev/octeon_fpavar.h>
 #include <mips/cavium/dev/octeon_gmxvar.h>
-#include <mips/cavium/dev/octeon_fauvar.h>
-#include <mips/cavium/dev/octeon_powvar.h>
 #include <mips/cavium/dev/octeon_ipdvar.h>
 #include <mips/cavium/dev/octeon_pipvar.h>
 #include <mips/cavium/dev/octeon_pkovar.h>
-#include <mips/cavium/dev/octeon_asxvar.h>
+#include <mips/cavium/dev/octeon_powvar.h>
 #include <mips/cavium/dev/octeon_smivar.h>
+
 #include <mips/cavium/dev/if_cnmacvar.h>
 
 /*
@@ -86,8 +108,6 @@ static void	cnmac_attach(device_t, devic
 static void	cnmac_pip_init(struct cnmac_softc *);
 static void	cnmac_ipd_init(struct cnmac_softc *);
 static void	cnmac_pko_init(struct cnmac_softc *);
-static void	cnmac_asx_init(struct cnmac_softc *);
-static void	cnmac_smi_init(struct cnmac_softc *);
 
 static void	cnmac_board_mac_addr(uint8_t *, size_t, struct cnmac_softc *);
 
@@ -107,11 +127,8 @@ static inline void cnmac_send_queue_add(
     uint64_t *);
 static inline void cnmac_send_queue_del(struct cnmac_softc *, struct mbuf **,
     uint64_t **);
-static inline int cnmac_buf_free_work(struct cnmac_softc *, uint64_t *,
-    uint64_t);
-static inline void cnmac_buf_ext_free_m(struct mbuf *, void *, size_t, void *);
-static inline void cnmac_buf_ext_free_ext(struct mbuf *, void *, size_t,
-    void *);
+static inline int cnmac_buf_free_work(struct cnmac_softc *, uint64_t *);
+static inline void cnmac_buf_ext_free(struct mbuf *, void *, size_t, void *);
 
 static int	cnmac_ioctl(struct ifnet *, u_long, void *);
 static void	cnmac_watchdog(struct ifnet *);
@@ -122,7 +139,8 @@ static void	cnmac_start(struct ifnet *);
 static inline int cnmac_send_cmd(struct cnmac_softc *, uint64_t, uint64_t,
     int *);
 static inline uint64_t	cnmac_send_makecmd_w1(int, paddr_t);
-static inline uint64_t	cnmac_send_makecmd_w0(uint64_t, uint64_t, size_t, int);
+static inline uint64_t	cnmac_send_makecmd_w0(uint64_t, uint64_t, size_t, int,
+    int);
 static inline int cnmac_send_makecmd_gbuf(struct cnmac_softc *, struct mbuf *,
     uint64_t *, int *);
 static inline int cnmac_send_makecmd(struct cnmac_softc *, struct mbuf *,
@@ -140,25 +158,12 @@ static void	cnmac_tick_misc(void *);
 
 static inline int cnmac_recv_mbuf(struct cnmac_softc *, uint64_t *,
     struct mbuf **);
-static inline int cnmac_recv_check_code(struct cnmac_softc *, uint64_t);
-static inline int cnmac_recv_check_jumbo(struct cnmac_softc *, uint64_t);
-static inline int cnmac_recv_check_link(struct cnmac_softc *, uint64_t);
 static inline int cnmac_recv_check(struct cnmac_softc *, uint64_t);
 static inline int cnmac_recv(struct cnmac_softc *, uint64_t *);
-static void	cnmac_recv_redir(struct ifnet *, struct mbuf *);
-static inline void cnmac_recv_intr(void *, uint64_t *);
+static int	cnmac_intr(void *);
 
-/* Device driver context */
-static struct	cnmac_softc *cnmac_gsc[GMX_PORT_NUNITS];
-static void	*cnmac_pow_recv_ih;
-
-/* sysctl'able parameters */
+/* device parameters */
 int		cnmac_param_pko_cmd_w0_n2 = 1;
-int		cnmac_param_pip_dyn_rs = 1;
-int		cnmac_param_redir = 0;
-int		cnmac_param_pktbuf = 0;
-int		cnmac_param_rate = 0;
-int		cnmac_param_intr = 0;
 
 CFATTACH_DECL_NEW(cnmac, sizeof(struct cnmac_softc),
     cnmac_match, cnmac_attach, NULL, NULL);
@@ -177,12 +182,14 @@ static const struct cnmac_pool_param {
 	_ENTRY(SG)
 #undef	_ENTRY
 };
-struct octfpa_buf	*cnmac_pools[8/* XXX */];
+struct octfpa_buf	*cnmac_pools[FPA_NPOOLS];
 #define	cnmac_fb_pkt	cnmac_pools[OCTEON_POOL_NO_PKT]
 #define	cnmac_fb_wqe	cnmac_pools[OCTEON_POOL_NO_WQE]
 #define	cnmac_fb_cmd	cnmac_pools[OCTEON_POOL_NO_CMD]
 #define	cnmac_fb_sg	cnmac_pools[OCTEON_POOL_NO_SG]
 
+static int	cnmac_npowgroups = 0;
+
 static void
 cnmac_buf_init(struct cnmac_softc *sc)
 {
@@ -225,12 +232,18 @@ cnmac_attach(device_t parent, device_t s
 	prop_object_t clk;
 	uint8_t enaddr[ETHER_ADDR_LEN];
 
+	if (cnmac_npowgroups >= OCTEON_POW_GROUP_MAX) {
+		printf(": out of POW groups\n");
+	}
+
 	sc->sc_dev = self;
 	sc->sc_regt = ga->ga_regt;
 	sc->sc_port = ga->ga_portno;
 	sc->sc_port_type = ga->ga_port_type;
 	sc->sc_gmx = ga->ga_gmx;
 	sc->sc_gmx_port = ga->ga_gmx_port;
+	sc->sc_smi = ga->ga_smi;
+	sc->sc_powgroup = cnmac_npowgroups++;
 
 	if (sc->sc_port >= CVMSEG_LM_ETHER_COUNT) {
 		/*
@@ -255,11 +268,9 @@ cnmac_attach(device_t parent, device_t s
 	}
 
 	cnmac_board_mac_addr(enaddr, sizeof(enaddr), sc);
-	printf("%s: Ethernet address %s\n", device_xname(sc->sc_dev),
+	printf("%s: Ethernet address %s\n", device_xname(self),
 	    ether_sprintf(enaddr));
 
-	cnmac_gsc[sc->sc_port] = sc;
-
 	SIMPLEQ_INIT(&sc->sc_sendq);
 	sc->sc_soft_req_thresh = 15/* XXX */;
 	sc->sc_ext_callback_cnt = 0;
@@ -269,19 +280,19 @@ cnmac_attach(device_t parent, device_t s
 	callout_init(&sc->sc_tick_misc_ch, 0);
 	callout_init(&sc->sc_tick_free_ch, 0);
 
+	const int dv_unit = device_unit(self);
 	octfau_op_init(&sc->sc_fau_done,
-	    OCTEON_CVMSEG_ETHER_OFFSET(sc->sc_port, csm_ether_fau_done),
-	    OCT_FAU_REG_ADDR_END - (8 * (sc->sc_port + 1))/* XXX */);
+	    OCTEON_CVMSEG_ETHER_OFFSET(dv_unit, csm_ether_fau_done),
+	    OCT_FAU_REG_ADDR_END - (8 * (dv_unit + 1))/* XXX */);
 	octfau_op_set_8(&sc->sc_fau_done, 0);
 
 	cnmac_pip_init(sc);
 	cnmac_ipd_init(sc);
 	cnmac_pko_init(sc);
-	cnmac_asx_init(sc);
-	cnmac_smi_init(sc);
+
+	cnmac_configure_common(sc);
 
 	sc->sc_gmx_port->sc_ipd = sc->sc_ipd;
-	sc->sc_gmx_port->sc_port_asx = sc->sc_asx;
 	sc->sc_gmx_port->sc_port_mii = &sc->sc_mii;
 	sc->sc_gmx_port->sc_port_ec = &sc->sc_ethercom;
 	/* XXX */
@@ -292,7 +303,7 @@ cnmac_attach(device_t parent, device_t s
 
 	cnmac_mediainit(sc);
 
-	strncpy(ifp->if_xname, device_xname(sc->sc_dev), sizeof(ifp->if_xname));
+	strncpy(ifp->if_xname, device_xname(self), sizeof(ifp->if_xname));
 	ifp->if_softc = sc;
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 	ifp->if_ioctl = cnmac_ioctl;
@@ -303,10 +314,18 @@ cnmac_attach(device_t parent, device_t s
 	IFQ_SET_MAXLEN(&ifp->if_snd, uimax(GATHER_QUEUE_SIZE, IFQ_MAXLEN));
 	IFQ_SET_READY(&ifp->if_snd);
 
-	/* XXX: not yet tx checksum */
+	
 	ifp->if_capabilities =
+#if 0	/* XXX: no tx checksum yet */
+	    IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx |
+	    IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx |
+	    IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx |
+	    IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_TCPv6_Rx |
+	    IFCAP_CSUM_UDPv6_Tx | IFCAP_CSUM_UDPv6_Rx;
+#else
 	    IFCAP_CSUM_IPv4_Rx | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx |
 	    IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx;
+#endif
 
 	/* 802.1Q VLAN-sized frames are supported */
 	sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU;
@@ -317,32 +336,25 @@ cnmac_attach(device_t parent, device_t s
 	ether_ifattach(ifp, enaddr);
 	octgmx_set_filter(sc->sc_gmx_port);
 
-	/* XXX */
-	sc->sc_rate_recv_check_link_cap.tv_sec = 1;
-	sc->sc_rate_recv_check_jumbo_cap.tv_sec = 1;
-	sc->sc_rate_recv_check_code_cap.tv_sec = 1;
-	sc->sc_rate_recv_fixup_odd_nibble_short_cap.tv_sec = 1;
-	sc->sc_rate_recv_fixup_odd_nibble_preamble_cap.tv_sec = 1;
-	sc->sc_rate_recv_fixup_odd_nibble_crc_cap.tv_sec = 1;
-	/* XXX */
-
 #if 1
 	cnmac_buf_init(sc);
 #endif
 
-	if (cnmac_pow_recv_ih == NULL)
-		cnmac_pow_recv_ih
-		    = octpow_intr_establish(OCTEON_POW_GROUP_PIP,
-			IPL_NET, cnmac_recv_intr, NULL, NULL);
+	sc->sc_ih = octeon_intr_establish(POW_WORKQ_IRQ(sc->sc_powgroup),
+	    IPL_NET, cnmac_intr, sc);
+	if (sc->sc_ih == NULL)
+		panic("%s: could not set up interrupt", device_xname(self));
 
 	dict = device_properties(sc->sc_gmx->sc_dev);
 
 	clk = prop_dictionary_get(dict, "rgmii-tx");
-	KASSERT(clk != NULL);
-	sc->sc_gmx_port->sc_clk_tx_setting = prop_number_signed_value(clk);
+	if (clk)
+		sc->sc_gmx_port->sc_clk_tx_setting =
+		    prop_number_signed_value(clk);
 	clk = prop_dictionary_get(dict, "rgmii-rx");
-	KASSERT(clk != NULL);
-	sc->sc_gmx_port->sc_clk_rx_setting = prop_number_signed_value(clk);
+	if (clk)
+		sc->sc_gmx_port->sc_clk_rx_setting =
+		    prop_number_signed_value(clk);
 }
 
 /* ---- submodules */
@@ -356,9 +368,10 @@ cnmac_pip_init(struct cnmac_softc *sc)
 	pip_aa.aa_port = sc->sc_port;
 	pip_aa.aa_regt = sc->sc_regt;
 	pip_aa.aa_tag_type = POW_TAG_TYPE_ORDERED/* XXX */;
-	pip_aa.aa_receive_group = OCTEON_POW_GROUP_PIP;
+	pip_aa.aa_receive_group = sc->sc_powgroup;
 	pip_aa.aa_ip_offset = sc->sc_ip_offset;
 	octpip_init(&pip_aa, &sc->sc_pip);
+	octpip_port_config(sc->sc_pip);
 }
 
 /* XXX */
@@ -388,28 +401,6 @@ cnmac_pko_init(struct cnmac_softc *sc)
 	octpko_init(&pko_aa, &sc->sc_pko);
 }
 
-/* XXX */
-static void
-cnmac_asx_init(struct cnmac_softc *sc)
-{
-	struct octasx_attach_args asx_aa;
-
-	asx_aa.aa_port = sc->sc_port;
-	asx_aa.aa_regt = sc->sc_regt;
-	octasx_init(&asx_aa, &sc->sc_asx);
-}
-
-static void
-cnmac_smi_init(struct cnmac_softc *sc)
-{
-	struct octsmi_attach_args smi_aa;
-
-	smi_aa.aa_port = sc->sc_port;
-	smi_aa.aa_regt = sc->sc_regt;
-	octsmi_init(&smi_aa, &sc->sc_smi);
-	octsmi_set_clock(sc->sc_smi, 0x1464ULL); /* XXX */
-}
-
 /* ---- XXX */
 
 #define	ADDR2UINT64(u, a) \
@@ -663,10 +654,11 @@ cnmac_send_queue_del(struct cnmac_softc 
 }
 
 static inline int
-cnmac_buf_free_work(struct cnmac_softc *sc, uint64_t *work, uint64_t word2)
+cnmac_buf_free_work(struct cnmac_softc *sc, uint64_t *work)
 {
+
 	/* XXX when jumbo frame */
-	if (ISSET(word2, PIP_WQE_WORD2_IP_BUFS)) {
+	if (ISSET(work[2], PIP_WQE_WORD2_IP_BUFS)) {
 		paddr_t addr;
 		paddr_t start_buffer;
 
@@ -682,35 +674,13 @@ cnmac_buf_free_work(struct cnmac_softc *
 }
 
 static inline void
-cnmac_buf_ext_free_m(struct mbuf *m, void *buf, size_t size, void *arg)
-{
-	uint64_t *work = (void *)arg;
-	int s = splnet();
-
-	octfpa_buf_put(cnmac_fb_wqe, work);
-
-	KASSERT(m != NULL);
-
-	pool_cache_put(mb_cache, m);
-
-	splx(s);
-}
-
-static inline void
-cnmac_buf_ext_free_ext(struct mbuf *m, void *buf, size_t size, void *arg)
+cnmac_buf_ext_free(struct mbuf *m, void *buf, size_t size, void *arg)
 {
-	uint64_t *work = (void *)arg;
-	int s = splnet();
-
-	octfpa_buf_put(cnmac_fb_wqe, work);
-
 	octfpa_buf_put(cnmac_fb_pkt, buf);
 
 	KASSERT(m != NULL);
 
 	pool_cache_put(mb_cache, m);
-
-	splx(s);
 }
 
 /* ---- ifnet interfaces */
@@ -742,18 +712,17 @@ cnmac_ioctl(struct ifnet *ifp, u_long cm
 		break;
 	default:
 		error = ether_ioctl(ifp, cmd, data);
-		if (error == ENETRESET) {
-			/*
-			 * Multicast list has changed; set the hardware filter
-			 * accordingly.
-			 */
-			if (ISSET(ifp->if_flags, IFF_RUNNING))
-				octgmx_set_filter(sc->sc_gmx_port);
-			error = 0;
-		}
 		break;
 	}
+
+	if (error == ENETRESET) {
+		if (ISSET(ifp->if_flags, IFF_RUNNING))
+			octgmx_set_filter(sc->sc_gmx_port);
+		error = 0;
+	}
+
 	cnmac_start(ifp);
+
 	splx(s);
 
 	return error;
@@ -762,8 +731,10 @@ cnmac_ioctl(struct ifnet *ifp, u_long cm
 /* ---- send (output) */
 
 static inline uint64_t
-cnmac_send_makecmd_w0(uint64_t fau0, uint64_t fau1, size_t len, int segs)
+cnmac_send_makecmd_w0(uint64_t fau0, uint64_t fau1, size_t len, int segs,
+    int ipoffp1)
 {
+
 	return octpko_cmd_word0(
 		OCT_FAU_OP_SIZE_64,		/* sz1 */
 		OCT_FAU_OP_SIZE_64,		/* sz0 */
@@ -779,9 +750,10 @@ cnmac_send_makecmd_w0(uint64_t fau0, uin
 static inline uint64_t
 cnmac_send_makecmd_w1(int size, paddr_t addr)
 {
+
 	return octpko_cmd_word1(
 		0, 0,				/* i, back */
-		FPA_GATHER_BUFFER_POOL,		/* pool */
+		OCTEON_POOL_NO_SG,		/* pool */
 		size, addr);			/* size, addr */
 }
 
@@ -798,11 +770,6 @@ cnmac_send_makecmd_gbuf(struct cnmac_sof
 		if (__predict_false(m->m_len == 0))
 			continue;
 
-#if 0
-		KASSERT(((uint32_t)m->m_data & (PAGE_SIZE - 1))
-		   == (kvtophys((vaddr_t)m->m_data) & (PAGE_SIZE - 1)));
-#endif
-
 		/* Aligned 4k */
 		laddr = (uintptr_t)m->m_data & (PAGE_SIZE - 1);
 
@@ -842,6 +809,7 @@ cnmac_send_makecmd(struct cnmac_softc *s
     uint64_t *gbuf, uint64_t *rpko_cmd_w0, uint64_t *rpko_cmd_w1)
 {
 	uint64_t pko_cmd_w0, pko_cmd_w1;
+	int ipoffp1;
 	int segs;
 	int result = 0;
 
@@ -852,6 +820,10 @@ cnmac_send_makecmd(struct cnmac_softc *s
 		goto done;
 	}
 
+	/*  Get the IP packet offset for TCP/UDP checksum offloading. */
+	ipoffp1 = (m->m_pkthdr.csum_flags & (M_CSUM_TCPv4 | M_CSUM_UDPv4))
+	    ? (ETHER_HDR_LEN + 1) : 0;
+
 	/*
 	 * segs == 1	-> link mode (single continuous buffer)
 	 *		   WORD1[size] is number of bytes pointed by segment
@@ -860,7 +832,7 @@ cnmac_send_makecmd(struct cnmac_softc *s
 	 *		   WORD1[size] is number of segments
 	 */
 	pko_cmd_w0 = cnmac_send_makecmd_w0(sc->sc_fau_done.fd_regno,
-	    0, m->m_pkthdr.len, segs);
+	    0, m->m_pkthdr.len, segs, ipoffp1);
 	if (segs == 1) {
 		pko_cmd_w1 = cnmac_send_makecmd_w1(
 		    m->m_pkthdr.len, kvtophys((vaddr_t)m->m_data));
@@ -1006,19 +978,8 @@ cnmac_start(struct ifnet *ifp)
 	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
 		goto last;
 
-	/* XXX assume that OCTEON doesn't buffer packets */
-	if (__predict_false(!octgmx_link_status(sc->sc_gmx_port))) {
-		/* Dequeue and drop them */
-		while (1) {
-			IFQ_DEQUEUE(&ifp->if_snd, m);
-			if (m == NULL)
-				break;
-
-			m_freem(m);
-			IF_DROP(&ifp->if_snd);
-		}
+	if (__predict_false(!octgmx_link_status(sc->sc_gmx_port)))
 		goto last;
-	}
 
 	for (;;) {
 		IFQ_POLL(&ifp->if_snd, m);
@@ -1068,22 +1029,6 @@ cnmac_start(struct ifnet *ifp)
 	if (wdc > 0)
 		octpko_op_doorbell_write(sc->sc_port, sc->sc_port, wdc);
 
-/*
- * Don't schedule send-buffer-free callout every time - those buffers are freed
- * by "free tick".  This makes some packets like NFS slower.
- */
-#ifdef CNMAC_USENFS
-	if (__predict_false(sc->sc_ext_callback_cnt > 0)) {
-		int timo;
-
-		/* ??? */
-		timo = hz - (100 * sc->sc_ext_callback_cnt);
-		if (timo < 10)
-			timo = 10;
-		callout_schedule(&sc->sc_tick_free_ch, timo);
-	}
-#endif
-
 last:
 	cnmac_send_queue_flush_fetch(sc);
 }
@@ -1152,12 +1097,11 @@ cnmac_stop(struct ifnet *ifp, int disabl
 	/* Mark the interface as down and cancel the watchdog timer. */
 	CLR(ifp->if_flags, IFF_RUNNING | IFF_OACTIVE);
 	ifp->if_timer = 0;
+
 }
 
 /* ---- misc */
 
-#define PKO_INDEX_MASK	((1ULL << 12/* XXX */) - 1)
-
 static int
 cnmac_reset(struct cnmac_softc *sc)
 {
@@ -1179,7 +1123,7 @@ cnmac_configure(struct cnmac_softc *sc)
 
 	octpko_port_config(sc->sc_pko);
 	octpko_port_enable(sc->sc_pko, 1);
-	octpip_port_config(sc->sc_pip);
+	octpow_config(sc->sc_pow, sc->sc_powgroup);
 
 	octgmx_tx_stats_rd_clr(sc->sc_gmx_port, 1);
 	octgmx_rx_stats_rd_clr(sc->sc_gmx_port, 1);
@@ -1199,13 +1143,8 @@ cnmac_configure_common(struct cnmac_soft
 	once = 1;
 
 	octipd_config(sc->sc_ipd);
-#ifdef CNMAC_IPD_RED
-	octipd_red(sc->sc_ipd, RECV_QUEUE_SIZE >> 2, RECV_QUEUE_SIZE >> 3);
-#endif
 	octpko_config(sc->sc_pko);
 
-	octpow_config(sc->sc_pow, OCTEON_POW_GROUP_PIP);
-
 	return 0;
 }
 
@@ -1215,10 +1154,9 @@ static inline int
 cnmac_recv_mbuf(struct cnmac_softc *sc, uint64_t *work, struct mbuf **rm)
 {
 	struct mbuf *m;
-	void (*ext_free)(struct mbuf *, void *, size_t, void *);
-	void *ext_buf;
+	vaddr_t addr;
+	vaddr_t ext_buf;
 	size_t ext_size;
-	void *data;
 	uint64_t word1 = work[1];
 	uint64_t word2 = work[2];
 	uint64_t word3 = work[3];
@@ -1226,41 +1164,26 @@ cnmac_recv_mbuf(struct cnmac_softc *sc, 
 	MGETHDR(m, M_NOWAIT, MT_DATA);
 	if (m == NULL)
 		return 1;
-	KASSERT(m != NULL);
 
-	if ((word2 & PIP_WQE_WORD2_IP_BUFS) == 0) {
-		/* Dynamic short */
-		ext_free = cnmac_buf_ext_free_m;
-		ext_buf = &work[4];
-		ext_size = 96;
+	octfpa_buf_put(cnmac_fb_wqe, work);
+
+	if (__SHIFTOUT(word2, PIP_WQE_WORD2_IP_BUFS) != 1)
+		panic("%s: expected one buffer, got %" PRId64, __func__,
+		    __SHIFTOUT(word2, PIP_WQE_WORD2_IP_BUFS));
 
-		data = &work[4 + sc->sc_ip_offset / sizeof(uint64_t)];
-	} else {
-		vaddr_t addr;
-		vaddr_t start_buffer;
 
 #ifdef __mips_n32
-		KASSERT((word3 & ~MIPS_PHYS_MASK) == 0);
-		addr = MIPS_PHYS_TO_KSEG0(word3 & PIP_WQE_WORD3_ADDR);
+	KASSERT((word3 & ~MIPS_PHYS_MASK) == 0);
+	addr = MIPS_PHYS_TO_KSEG0(word3 & PIP_WQE_WORD3_ADDR);
 #else
-		addr = MIPS_PHYS_TO_XKPHYS_CACHED(word3 & PIP_WQE_WORD3_ADDR);
+	addr = MIPS_PHYS_TO_XKPHYS_CACHED(word3 & PIP_WQE_WORD3_ADDR);
 #endif
-		start_buffer = addr & ~(2048 - 1);
 
-		ext_free = cnmac_buf_ext_free_ext;
-		ext_buf = (void *)start_buffer;
-		ext_size = 2048;
-
-		data = (void *)addr;
-	}
+	ext_size = OCTEON_POOL_SIZE_PKT;
+	ext_buf = addr & ~(ext_size - 1);
+	MEXTADD(m, ext_buf, ext_size, 0, cnmac_buf_ext_free, NULL);
 
-	/* Embed sc pointer into work[0] for _ext_free evcnt */
-	work[0] = (uintptr_t)sc;
-
-	MEXTADD(m, ext_buf, ext_size, 0, ext_free, work);
-	KASSERT(ISSET(m->m_flags, M_EXT));
-
-	m->m_data = data;
+	m->m_data = (void *)addr;
 	m->m_len = m->m_pkthdr.len = (word1 & PIP_WQE_WORD1_LEN) >> 48;
 	m_set_rcvif(m, &sc->sc_ethercom.ec_if);
 
@@ -1275,101 +1198,34 @@ cnmac_recv_mbuf(struct cnmac_softc *sc, 
 }
 
 static inline int
-cnmac_recv_check_code(struct cnmac_softc *sc, uint64_t word2)
+cnmac_recv_check(struct cnmac_softc *sc, uint64_t word2)
 {
-	uint64_t opecode = word2 & PIP_WQE_WORD2_NOIP_OPECODE;
+	static struct timeval rxerr_log_interval = { 0, 2500000 };
+	uint64_t opecode;
 
 	if (__predict_true(!ISSET(word2, PIP_WQE_WORD2_NOIP_RE)))
 		return 0;
 
+	opecode = word2 & PIP_WQE_WORD2_NOIP_OPECODE;
+	if ((sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) &&
+	    ratecheck(&sc->sc_rxerr_log_last, &rxerr_log_interval))
+		log(LOG_DEBUG, "%s: rx error (%"PRId64")\n",
+		    device_xname(sc->sc_dev), opecode);
+
 	/* This error is harmless */
-	if (opecode == PIP_OVER_ERR)
+	if (opecode == PIP_WQE_WORD2_RE_OPCODE_OVRRUN)
 		return 0;
 
 	return 1;
 }
 
 static inline int
-cnmac_recv_check_jumbo(struct cnmac_softc *sc, uint64_t word2)
-{
-	if (__predict_false((word2 & PIP_WQE_WORD2_IP_BUFS) > (1ULL << 56)))
-		return 1;
-	return 0;
-}
-
-static inline int
-cnmac_recv_check_link(struct cnmac_softc *sc, uint64_t word2)
-{
-	if (__predict_false(!octgmx_link_status(sc->sc_gmx_port)))
-		return 1;
-	return 0;
-}
-
-static inline int
-cnmac_recv_check(struct cnmac_softc *sc, uint64_t word2)
-{
-	if (__predict_false(cnmac_recv_check_link(sc, word2)) != 0) {
-		if (ratecheck(&sc->sc_rate_recv_check_link_last,
-		    &sc->sc_rate_recv_check_link_cap))
-			log(LOG_DEBUG,
-			    "%s: link is not up, the packet was dropped\n",
-			    device_xname(sc->sc_dev));
-		return 1;
-	}
-
-#if 0 /* XXX Performance tuning (Jumbo-frame is not supported yet!) */
-	if (__predict_false(cnmac_recv_check_jumbo(sc, word2)) != 0) {
-		/* XXX jumbo frame */
-		if (ratecheck(&sc->sc_rate_recv_check_jumbo_last,
-		    &sc->sc_rate_recv_check_jumbo_cap))
-			log(LOG_DEBUG,
-			    "jumbo frame was received\n");
-		return 1;
-	}
-#endif
-
-	if (__predict_false(cnmac_recv_check_code(sc, word2)) != 0) {
-
-		if ((word2 & PIP_WQE_WORD2_NOIP_OPECODE) ==
-				PIP_WQE_WORD2_RE_OPCODE_LENGTH) {
-			/* No logging */
-			/* XXX increment special error count */
-		} else if ((word2 & PIP_WQE_WORD2_NOIP_OPECODE) ==
-				PIP_WQE_WORD2_RE_OPCODE_PARTIAL) {
-			/* Not an error, it's because of overload */
-		} else {
-
-			if (ratecheck(&sc->sc_rate_recv_check_code_last,
-			    &sc->sc_rate_recv_check_code_cap))
-				log(LOG_WARNING,
-				    "%s: reception error, packet dropped "
-				    "(error code = %" PRId64 ")\n",
-				    device_xname(sc->sc_dev), word2 & PIP_WQE_WORD2_NOIP_OPECODE);
-		}
-		return 1;
-	}
-
-	return 0;
-}
-
-static inline int
 cnmac_recv(struct cnmac_softc *sc, uint64_t *work)
 {
-	int result = 0;
 	struct ifnet *ifp;
 	struct mbuf *m;
 	uint64_t word2;
 
-	/* XXX XXX XXX */
-	/*
-	 * Performance tuning
-	 * pre-send iobdma request
-	 */
-	if (sc->sc_soft_req_cnt > sc->sc_soft_req_thresh) {
-		cnmac_send_queue_flush_prefetch(sc);
-	}
-	/* XXX XXX XXX */
-
 	KASSERT(sc != NULL);
 	KASSERT(work != NULL);
 
@@ -1378,17 +1234,16 @@ cnmac_recv(struct cnmac_softc *sc, uint6
 
 	KASSERT(ifp != NULL);
 
+	if (!ISSET(ifp->if_flags, IFF_RUNNING))
+		goto drop;
+
 	if (__predict_false(cnmac_recv_check(sc, word2) != 0)) {
 		if_statinc(ifp, if_ierrors);
-		result = 1;
-		cnmac_buf_free_work(sc, work, word2);
 		goto drop;
 	}
 
 	if (__predict_false(cnmac_recv_mbuf(sc, work, &m) != 0)) {
 		if_statinc(ifp, if_ierrors);
-		result = 1;
-		cnmac_buf_free_work(sc, work, word2);
 		goto drop;
 	}
 
@@ -1398,90 +1253,60 @@ cnmac_recv(struct cnmac_softc *sc, uint6
 
 	octipd_offload(word2, m->m_data, &m->m_pkthdr.csum_flags);
 
-	/* XXX XXX XXX */
-	if (sc->sc_soft_req_cnt > sc->sc_soft_req_thresh) {
-		cnmac_send_queue_flush_fetch(sc);
-		cnmac_send_queue_flush(sc);
-	}
-
-	/* XXX XXX XXX */
-	if (sc->sc_flush)
-		cnmac_send_queue_flush_sync(sc);
-	/* XXX XXX XXX */
-
 	if_percpuq_enqueue(ifp->if_percpuq, m);
 
 	return 0;
 
 drop:
-	/* XXX XXX XXX */
-	if (sc->sc_soft_req_cnt > sc->sc_soft_req_thresh) {
-		cnmac_send_queue_flush_fetch(sc);
-	}
-	/* XXX XXX XXX */
-
-	return result;
+	cnmac_buf_free_work(sc, work);
+	return 1;
 }
 
-static void
-cnmac_recv_redir(struct ifnet *ifp, struct mbuf *m)
+static int
+cnmac_intr(void *arg)
 {
-	struct cnmac_softc *rsc = ifp->if_softc;
-	struct cnmac_softc *sc = NULL;
-	int i, wdc = 0;
-
-	for (i = 0; i < 3 /* XXX */; i++) {
-		if (rsc->sc_redir & (1 << i))
-			sc = cnmac_gsc[i];
-	}
-
-	if (sc == NULL) {
-		m_freem(m);
-		return;
-	}
-	cnmac_send_queue_flush_prefetch(sc);
+	struct cnmac_softc *sc = arg;
+	uint64_t *work;
+	uint64_t wqmask = __BIT(sc->sc_powgroup);
+	uint32_t coreid = 0;	/* XXX octeon_get_coreid() */
+	uint32_t port;
+
+	_POW_WR8(sc->sc_pow, POW_PP_GRP_MSK_OFFSET(coreid), wqmask);
+
+	octpow_tag_sw_wait();
+	octpow_work_request_async(OCTEON_CVMSEG_OFFSET(csm_pow_intr),
+	    POW_NO_WAIT);
 
-	cnmac_send_queue_flush_fetch(sc);
+	for (;;) {
+		work = (uint64_t *)octpow_work_response_async(
+		    OCTEON_CVMSEG_OFFSET(csm_pow_intr));
+		if (work == NULL)
+			break;
 
-	if (cnmac_send_queue_is_full(sc)) {
-		m_freem(m);
-		return;
-	}
-	if (sc->sc_soft_req_cnt > sc->sc_soft_req_thresh)
-		cnmac_send_queue_flush(sc);
+		octpow_tag_sw_wait();
+		octpow_work_request_async(OCTEON_CVMSEG_OFFSET(csm_pow_intr),
+		    POW_NO_WAIT);
+
+		port = __SHIFTOUT(work[1], PIP_WQE_WORD1_IPRT);
+		if (port != sc->sc_port) {
+			printf("%s: unexpected wqe port %u, should be %u\n",
+			    device_xname(sc->sc_dev), port, sc->sc_port);
+			goto wqe_error;
+		}
 
-	if (cnmac_send(sc, m, &wdc)) {
-		IF_DROP(&ifp->if_snd);
-		m_freem(m);
-	} else {
-		octpko_op_doorbell_write(sc->sc_port, sc->sc_port, wdc);
-		sc->sc_soft_req_cnt++;
+		(void)cnmac_recv(sc, work);
 	}
 
-	if (sc->sc_flush)
-		cnmac_send_queue_flush_sync(sc);
-}
-
-static inline void
-cnmac_recv_intr(void *data, uint64_t *work)
-{
-	struct cnmac_softc *sc;
-	int port;
-
-	KASSERT(work != NULL);
-
-	port = (work[1] & PIP_WQE_WORD1_IPRT) >> 42;
+	_POW_WR8(sc->sc_pow, POW_WQ_INT_OFFSET, wqmask);
 
-	KASSERT(port < GMX_PORT_NUNITS);
-
-	sc = cnmac_gsc[port];
-
-	KASSERT(sc != NULL);
-	KASSERT(port == sc->sc_port);
-
-	/* XXX process all work queue entries anyway */
+	return 1;
 
-	(void)cnmac_recv(sc, work);
+wqe_error:
+	printf("word0: 0x%016" PRIx64 "\n", work[0]);
+	printf("word1: 0x%016" PRIx64 "\n", work[1]);
+	printf("word2: 0x%016" PRIx64 "\n", work[2]);
+	printf("word3: 0x%016" PRIx64 "\n", work[3]);
+	panic("wqe_error");
 }
 
 /* ---- tick */
@@ -1545,291 +1370,3 @@ cnmac_tick_misc(void *arg)
 
 	callout_schedule(&sc->sc_tick_misc_ch, hz);
 }
-
-/* ---- Odd nibble preamble workaround (software CRC processing) */
-
-/* ---- sysctl */
-
-static int	cnmac_sysctl_verify(SYSCTLFN_ARGS);
-static int	cnmac_sysctl_pool(SYSCTLFN_ARGS);
-static int	cnmac_sysctl_rd(SYSCTLFN_ARGS);
-
-static int	cnmac_sysctl_pkocmdw0n2_num;
-static int	cnmac_sysctl_pipdynrs_num;
-static int	cnmac_sysctl_redir_num;
-static int	cnmac_sysctl_pkt_pool_num;
-static int	cnmac_sysctl_wqe_pool_num;
-static int	cnmac_sysctl_cmd_pool_num;
-static int	cnmac_sysctl_sg_pool_num;
-static int	cnmac_sysctl_pktbuf_num;
-
-/*
- * Set up sysctl(3) MIB, hw.cnmac.*.
- */
-SYSCTL_SETUP(sysctl_octeon_eth, "sysctl cnmac subtree setup")
-{
-	int rc;
-	int cnmac_sysctl_root_num;
-	const struct sysctlnode *node;
-
-	if ((rc = sysctl_createv(clog, 0, NULL, NULL,
-		    0, CTLTYPE_NODE, "hw", NULL,
-		    NULL, 0, NULL, 0, CTL_HW, CTL_EOL)) != 0) {
-		goto err;
-	}
-
-	if ((rc = sysctl_createv(clog, 0, NULL, &node,
-		    0, CTLTYPE_NODE, "cnmac",
-		    SYSCTL_DESCR("cnmac interface controls"),
-		    NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) {
-		goto err;
-	}
-
-	cnmac_sysctl_root_num = node->sysctl_num;
-
-	if ((rc = sysctl_createv(clog, 0, NULL, &node,
-		    CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
-		    CTLTYPE_INT, "pko_cmd_w0_n2",
-		    SYSCTL_DESCR("PKO command WORD0 N2 bit"),
-		    cnmac_sysctl_verify, 0,
-		    &cnmac_param_pko_cmd_w0_n2,
-		    0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE,
-		    CTL_EOL)) != 0) {
-		goto err;
-	}
-
-	cnmac_sysctl_pkocmdw0n2_num = node->sysctl_num;
-
-	if ((rc = sysctl_createv(clog, 0, NULL, &node,
-		    CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
-		    CTLTYPE_INT, "pip_dyn_rs",
-		    SYSCTL_DESCR("PIP dynamic short in WQE"),
-		    cnmac_sysctl_verify, 0,
-		    &cnmac_param_pip_dyn_rs,
-		    0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE,
-		    CTL_EOL)) != 0) {
-		goto err;
-	}
-
-	cnmac_sysctl_pipdynrs_num = node->sysctl_num;
-
-	if ((rc = sysctl_createv(clog, 0, NULL, &node,
-		    CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
-		    CTLTYPE_INT, "redir",
-		    SYSCTL_DESCR("input port redirection"),
-		    cnmac_sysctl_verify, 0,
-		    &cnmac_param_redir,
-		    0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE,
-		    CTL_EOL)) != 0) {
-		goto err;
-	}
-
-	cnmac_sysctl_redir_num = node->sysctl_num;
-
-	if ((rc = sysctl_createv(clog, 0, NULL, &node,
-		    CTLFLAG_PERMANENT,
-		    CTLTYPE_INT, "pkt_pool",
-		    SYSCTL_DESCR("packet pool available"),
-		    cnmac_sysctl_pool, 0, NULL,
-		    0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE,
-		    CTL_EOL)) != 0) {
-		goto err;
-	}
-
-	cnmac_sysctl_pkt_pool_num = node->sysctl_num;
-
-	if ((rc = sysctl_createv(clog, 0, NULL, &node,
-		    CTLFLAG_PERMANENT,
-		    CTLTYPE_INT, "wqe_pool",
-		    SYSCTL_DESCR("wqe pool available"),
-		    cnmac_sysctl_pool, 0, NULL,
-		    0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE,
-		    CTL_EOL)) != 0) {
-		goto err;
-	}
-
-	cnmac_sysctl_wqe_pool_num = node->sysctl_num;
-
-	if ((rc = sysctl_createv(clog, 0, NULL, &node,
-		    CTLFLAG_PERMANENT,
-		    CTLTYPE_INT, "cmd_pool",
-		    SYSCTL_DESCR("cmd pool available"),
-		    cnmac_sysctl_pool, 0, NULL,
-		    0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE,
-		    CTL_EOL)) != 0) {
-		goto err;
-	}
-
-	cnmac_sysctl_cmd_pool_num = node->sysctl_num;
-
-	if ((rc = sysctl_createv(clog, 0, NULL, &node,
-		    CTLFLAG_PERMANENT,
-		    CTLTYPE_INT, "sg_pool",
-		    SYSCTL_DESCR("sg pool available"),
-		    cnmac_sysctl_pool, 0, NULL,
-		    0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE,
-		    CTL_EOL)) != 0) {
-		goto err;
-	}
-
-	cnmac_sysctl_sg_pool_num = node->sysctl_num;
-
-	if ((rc = sysctl_createv(clog, 0, NULL, &node,
-		    CTLFLAG_PERMANENT | CTLFLAG_READONLY,
-		    CTLTYPE_INT, "pktbuf",
-		    SYSCTL_DESCR("input packet buffer size on POW"),
-		    cnmac_sysctl_rd, 0,
-		    &cnmac_param_pktbuf,
-		    0, CTL_HW, cnmac_sysctl_root_num, CTL_CREATE,
-		    CTL_EOL)) != 0) {
-		goto err;
-	}
-
-	cnmac_sysctl_pktbuf_num = node->sysctl_num;
-
-	return;
-
-err:
-	aprint_error("%s: syctl_createv failed (rc = %d)\n", __func__, rc);
-}
-
-static int
-cnmac_sysctl_verify(SYSCTLFN_ARGS)
-{
-	int error, v;
-	struct sysctlnode node;
-	struct cnmac_softc *sc;
-	int i;
-	int s;
-
-	node = *rnode;
-	v = *(int *)rnode->sysctl_data;
-	node.sysctl_data = &v;
-	error = sysctl_lookup(SYSCTLFN_CALL(&node));
-	if (error || newp == NULL)
-		return error;
-
-	if (node.sysctl_num == cnmac_sysctl_pkocmdw0n2_num) {
-		if (v < 0 || v > 1)
-			return EINVAL;
-		*(int *)rnode->sysctl_data = v;
-		return 0;
-	}
-
-	if (node.sysctl_num == cnmac_sysctl_pipdynrs_num) {
-		if (v < 0 || v > 1)
-			return EINVAL;
-		*(int *)rnode->sysctl_data = v;
-		s = splnet();
-		for (i = 0; i < 3/* XXX */; i++) {
-			sc = cnmac_gsc[i];	/* XXX */
-			octpip_prt_cfg_enable(sc->sc_pip,
-			    PIP_PRT_CFGN_DYN_RS, v);
-		}
-		splx(s);
-		return 0;
-	}
-
-	if (node.sysctl_num == cnmac_sysctl_redir_num) {
-		if (v & ~((0x7 << (4 * 0)) | (0x7 << (4 * 1)) | (0x7 << (4 * 2))))
-			return EINVAL;
-		*(int *)rnode->sysctl_data = v;
-		s = splnet();
-		for (i = 0; i < 3/* XXX */; i++) {
-			struct ifnet *ifp;
-
-			sc = cnmac_gsc[i];	/* XXX */
-			ifp = &sc->sc_ethercom.ec_if;
-
-			sc->sc_redir
-			    = (cnmac_param_redir >> (4 * i)) & 0x7;
-			if (sc->sc_redir == 0) {
-				if (ISSET(ifp->if_flags, IFF_PROMISC)) {
-					CLR(ifp->if_flags, IFF_PROMISC);
-					cnmac_mii_statchg(ifp);
-					/* octgmx_set_filter(sc->sc_gmx_port); */
-				}
-				ifp->_if_input = ether_input;
-			}
-			else {
-				if (!ISSET(ifp->if_flags, IFF_PROMISC)) {
-					SET(ifp->if_flags, IFF_PROMISC);
-					cnmac_mii_statchg(ifp);
-					/* octgmx_set_filter(sc->sc_gmx_port); */
-				}
-				ifp->_if_input = cnmac_recv_redir;
-			}
-		}
-		splx(s);
-		return 0;
-	}
-
-	return EINVAL;
-}
-
-static int
-cnmac_sysctl_pool(SYSCTLFN_ARGS)
-{
-	int error, newval = 0;
-	struct sysctlnode node;
-	int s;
-
-	node = *rnode;
-	node.sysctl_data = &newval;
-	s = splnet();
-	if (node.sysctl_num == cnmac_sysctl_pkt_pool_num) {
-		error = octfpa_available_fpa_pool(&newval,
-		    OCTEON_POOL_NO_PKT);
-	} else if (node.sysctl_num == cnmac_sysctl_wqe_pool_num) {
-		error = octfpa_available_fpa_pool(&newval,
-		    OCTEON_POOL_NO_WQE);
-	} else if (node.sysctl_num == cnmac_sysctl_cmd_pool_num) {
-		error = octfpa_available_fpa_pool(&newval,
-		    OCTEON_POOL_NO_CMD);
-	} else if (node.sysctl_num == cnmac_sysctl_sg_pool_num) {
-		error = octfpa_available_fpa_pool(&newval,
-		    OCTEON_POOL_NO_SG);
-	} else {
-		splx(s);
-		return EINVAL;
-	}
-	splx(s);
-	if (error)
-		return error;
-	error = sysctl_lookup(SYSCTLFN_CALL(&node));
-	if (error || newp == NULL)
-		return error;
-
-	return 0;
-}
-
-static int
-cnmac_sysctl_rd(SYSCTLFN_ARGS)
-{
-	int error, v;
-	struct sysctlnode node;
-	int s;
-
-	node = *rnode;
-	v = *(int *)rnode->sysctl_data;
-	node.sysctl_data = &v;
-	error = sysctl_lookup(SYSCTLFN_CALL(&node));
-	if (error || newp != NULL)
-		return error;
-
-	if (node.sysctl_num == cnmac_sysctl_pktbuf_num) {
-		uint64_t tmp;
-		int n;
-
-		s = splnet();
-		tmp = octfpa_query(0);
-		n = (int)tmp;
-		splx(s);
-		*(int *)rnode->sysctl_data = n;
-		cnmac_param_pktbuf = n;
-		*(int *)oldp = n;
-		return 0;
-	}
-
-	return EINVAL;
-}

Index: src/sys/arch/mips/cavium/dev/if_cnmacvar.h
diff -u src/sys/arch/mips/cavium/dev/if_cnmacvar.h:1.3 src/sys/arch/mips/cavium/dev/if_cnmacvar.h:1.4
--- src/sys/arch/mips/cavium/dev/if_cnmacvar.h:1.3	Mon Jun 22 02:26:19 2020
+++ src/sys/arch/mips/cavium/dev/if_cnmacvar.h	Tue Jun 23 05:17:13 2020
@@ -1,32 +1,28 @@
-/*	$NetBSD: if_cnmacvar.h,v 1.3 2020/06/22 02:26:19 simonb Exp $	*/
+/*	$NetBSD: if_cnmacvar.h,v 1.4 2020/06/23 05:17:13 simonb Exp $	*/
 
 #undef DEBUG
-#undef TENBASET_DBG
-#undef REGISTER_DUMP
 #ifdef DEBUG
-#define dprintf printf
+#define	dprintf printf
 #else
-#define dprintf(...)
+#define	dprintf(...)
 #endif
 
-#define IS_MAC_MULTICASTBIT(addr) \
+#define	IS_MAC_MULTICASTBIT(addr) \
         ((addr)[0] & 0x01)
 
-#define SEND_QUEUE_SIZE		(32)
-#define GATHER_QUEUE_SIZE	(1024)
-#define FREE_QUEUE_SIZE		GATHER_QUEUE_SIZE
-#define RECV_QUEUE_SIZE		(GATHER_QUEUE_SIZE * 2)
+#define	SEND_QUEUE_SIZE		(32)
+#define	GATHER_QUEUE_SIZE	(1024)
+#define	FREE_QUEUE_SIZE		GATHER_QUEUE_SIZE
+#define	RECV_QUEUE_SIZE		(GATHER_QUEUE_SIZE * 2)
 
-#ifdef CNMAC_FIXUP_ODD_NIBBLE_DYNAMIC
-#define PROC_NIBBLE_SOFT_THRESHOLD 2000
-#endif
+/* Number of mbufs per port to keep in the packet pool */
+#define	CNMAC_MBUFS_PER_PORT	256
 
 /* XXX MUST BE REPLACED WITH BUS_DMA!!! */
 paddr_t kvtophys(vaddr_t);
 /* XXX MUST BE REPLACED WITH BUS_DMA!!! */
 
 struct _send_queue_entry;
-struct octasx_softc;
 struct octsmi_softc;
 struct octgmx_port_softc;
 struct octipd_softc;
@@ -41,22 +37,11 @@ struct cnmac_softc {
 	bus_space_tag_t		sc_regt;
 	bus_dma_tag_t		sc_dmat;
 
-#if 1
-	/* XXX backward compatibility; debugging purpose only */
-	bus_space_handle_t      sc_gmx_regh;
-	bus_space_handle_t      sc_gmx_port_regh;
-	bus_space_handle_t      sc_asx_regh;
-	bus_space_handle_t      sc_pow_regh;
-	bus_space_handle_t      sc_fpa_regh;
-	bus_space_handle_t      sc_smi_regh;
-	bus_space_handle_t      sc_pip_regh;
-#endif
+	void			*sc_ih;
 
-	void			*sc_pow_recv_ih;
 	struct octpip_softc	*sc_pip;
 	struct octipd_softc	*sc_ipd;
 	struct octpko_softc	*sc_pko;
-	struct octasx_softc	*sc_asx;
 	struct octsmi_softc	*sc_smi;
 	struct octgmx_softc	*sc_gmx;
 	struct octgmx_port_softc
@@ -71,10 +56,6 @@ struct cnmac_softc {
 	struct callout		sc_tick_misc_ch;
 	struct callout		sc_tick_free_ch;
 
-#ifdef CNMAC_INTR_FEEDBACK
-	struct callout		sc_resume_ch;
-#endif
-
 	int64_t			sc_soft_req_cnt;
 	int64_t			sc_soft_req_thresh;
 	int64_t			sc_hard_done_cnt;
@@ -87,6 +68,7 @@ struct cnmac_softc {
 	uint32_t		sc_port;
 	uint32_t		sc_port_type;
 	uint32_t		sc_init_flag;
+	int			sc_powgroup;
 
 	/*
 	 * Redirection - received (input) packets are redirected (directly sent)
@@ -106,17 +88,7 @@ struct cnmac_softc {
 
 	size_t			sc_ip_offset;
 
-	struct timeval		sc_rate_recv_check_link_last;
-	struct timeval		sc_rate_recv_check_link_cap;
-	struct timeval		sc_rate_recv_check_jumbo_last;
-	struct timeval		sc_rate_recv_check_jumbo_cap;
-	struct timeval		sc_rate_recv_check_code_last;
-	struct timeval		sc_rate_recv_check_code_cap;
-	struct timeval		sc_rate_recv_fixup_odd_nibble_short_last;
-	struct timeval		sc_rate_recv_fixup_odd_nibble_short_cap;
-	struct timeval		sc_rate_recv_fixup_odd_nibble_preamble_last;
-	struct timeval		sc_rate_recv_fixup_odd_nibble_preamble_cap;
-	struct timeval		sc_rate_recv_fixup_odd_nibble_crc_last;
-	struct timeval		sc_rate_recv_fixup_odd_nibble_crc_cap;
+	struct timeval		sc_rxerr_log_last;
+
 	int			sc_quirks;
 };

Index: src/sys/arch/mips/cavium/dev/octeon_gmx.c
diff -u src/sys/arch/mips/cavium/dev/octeon_gmx.c:1.14 src/sys/arch/mips/cavium/dev/octeon_gmx.c:1.15
--- src/sys/arch/mips/cavium/dev/octeon_gmx.c:1.14	Mon Jun 22 02:26:20 2020
+++ src/sys/arch/mips/cavium/dev/octeon_gmx.c	Tue Jun 23 05:17:13 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: octeon_gmx.c,v 1.14 2020/06/22 02:26:20 simonb Exp $	*/
+/*	$NetBSD: octeon_gmx.c,v 1.15 2020/06/23 05:17:13 simonb Exp $	*/
 
 /*
  * Copyright (c) 2007 Internet Initiative Japan, Inc.
@@ -26,19 +26,12 @@
  * SUCH DAMAGE.
  */
 
-/*
- *  support GMX0 interface only
- *  take no thought for other GMX interface
- */
-
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: octeon_gmx.c,v 1.14 2020/06/22 02:26:20 simonb Exp $");
-
-#include "opt_octeon.h"
+__KERNEL_RCSID(0, "$NetBSD: octeon_gmx.c,v 1.15 2020/06/23 05:17:13 simonb Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
-#include <sys/types.h>
+#include <sys/bus.h>
 #include <sys/cpu.h>
 #include <sys/device.h>
 #include <sys/lock.h>
@@ -48,14 +41,35 @@ __KERNEL_RCSID(0, "$NetBSD: octeon_gmx.c
 
 #include <mips/locore.h>
 #include <mips/include/cpuregs.h>
-#include <sys/bus.h>
 
+#include <mips/cavium/dev/octeon_asxvar.h>
 #include <mips/cavium/dev/octeon_ciureg.h>
 #include <mips/cavium/dev/octeon_gmxreg.h>
-#include <mips/cavium/include/iobusvar.h>
-#include <mips/cavium/dev/octeon_ipdvar.h>
-#include <mips/cavium/dev/octeon_asxvar.h>
 #include <mips/cavium/dev/octeon_gmxvar.h>
+#include <mips/cavium/dev/octeon_ipdvar.h>
+#include <mips/cavium/dev/octeon_pipvar.h>
+#include <mips/cavium/dev/octeon_smivar.h>
+
+#include <mips/cavium/include/iobusvar.h>
+
+/*
+ * CNnnXX packet interface
+ *
+ *
+ * CN30XX  - 1 GMX interface  x 3 ports
+ * CN31XX  - 1 GMX interface  x 3 ports
+ * CN38XX  - 2 GMX interfaces x 4 ports
+ * CN50XX  - 1 GMX interface  x 3 ports
+ * CN52XX  - 1 GMX interface  x 4 ports
+ * CN56XX  - 2 GMX interfaces x 4 ports
+ * CN58XX  - 2 GMX interfaces x 4 ports
+ * CN61XX  - 2 GMX interfaces x 4 ports
+ * CN63XX  - 1 GMX interface  x 4 ports
+ * CN66XX  - 2 GMX interfaces x 4 ports
+ * CN68XX  - 5 GMX interfaces x 4 ports
+ * CN70XX  - 2 GMX interfaces x 4 ports
+ * CNF71XX - 1 GMX interface  x 2 ports
+ */
 
 #define	dprintf(...)
 #define	CNMAC_KASSERT	KASSERT
@@ -83,22 +97,30 @@ __KERNEL_RCSID(0, "$NetBSD: octeon_gmx.c
 #define	_GMX_PORT_WR8(sc, off, v) \
 	bus_space_write_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_regh, (off), (v))
 
+#define PCS_READ_8(sc, reg) \
+	bus_space_read_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_pcs_regh, (reg))
+#define PCS_WRITE_8(sc, reg, val) \
+	bus_space_write_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_pcs_regh, (reg), (val))
+
 struct octgmx_port_ops {
 	int	(*port_ops_enable)(struct octgmx_port_softc *, int);
 	int	(*port_ops_speed)(struct octgmx_port_softc *);
 	int	(*port_ops_timing)(struct octgmx_port_softc *);
-	int	(*port_ops_set_mac_addr)(struct octgmx_port_softc *, uint8_t *,
-		    uint64_t);
-	int	(*port_ops_set_filter)(struct octgmx_port_softc *);
 };
 
 static int	octgmx_match(device_t, struct cfdata *, void *);
 static void	octgmx_attach(device_t, device_t, void *);
 static int	octgmx_print(void *, const char *);
-static int      octgmx_submatch(device_t, struct cfdata *, const int *, void *);
 static int	octgmx_init(struct octgmx_softc *);
+
+static int	octgmx_link_enable(struct octgmx_port_softc *, int);
 static int	octgmx_rx_frm_ctl_xable(struct octgmx_port_softc *, uint64_t,
 		    int);
+static void	octgmx_tx_int_enable(struct octgmx_port_softc *, int);
+static void	octgmx_rx_int_enable(struct octgmx_port_softc *, int);
+static int	octgmx_rx_frm_ctl_enable(struct octgmx_port_softc *, uint64_t);
+static int	octgmx_rx_frm_ctl_disable(struct octgmx_port_softc *, uint64_t);
+static int	octgmx_tx_thresh(struct octgmx_port_softc *, int);
 
 static int	octgmx_rgmii_enable(struct octgmx_port_softc *, int);
 static int	octgmx_rgmii_speed(struct octgmx_port_softc *);
@@ -106,9 +128,10 @@ static int	octgmx_rgmii_speed_newlink(st
 		    uint64_t *);
 static int	octgmx_rgmii_speed_speed(struct octgmx_port_softc *);
 static int	octgmx_rgmii_timing(struct octgmx_port_softc *);
-static int	octgmx_rgmii_set_mac_addr(struct octgmx_port_softc *, uint8_t *,
-		    uint64_t);
-static int	octgmx_rgmii_set_filter(struct octgmx_port_softc *);
+
+static int	octgmx_sgmii_enable(struct octgmx_port_softc *, int);
+static int	octgmx_sgmii_speed(struct octgmx_port_softc *);
+static int	octgmx_sgmii_timing(struct octgmx_port_softc *);
 
 static const int	octgmx_rx_adr_cam_regs[] = {
 	GMX0_RX0_ADR_CAM0, GMX0_RX0_ADR_CAM1, GMX0_RX0_ADR_CAM2,
@@ -123,16 +146,18 @@ struct octgmx_port_ops octgmx_port_ops_g
 	.port_ops_enable = octgmx_rgmii_enable,
 	.port_ops_speed = octgmx_rgmii_speed,
 	.port_ops_timing = octgmx_rgmii_timing,
-	.port_ops_set_mac_addr = octgmx_rgmii_set_mac_addr,
-	.port_ops_set_filter = octgmx_rgmii_set_filter
 };
 
 struct octgmx_port_ops octgmx_port_ops_rgmii = {
 	.port_ops_enable = octgmx_rgmii_enable,
 	.port_ops_speed = octgmx_rgmii_speed,
 	.port_ops_timing = octgmx_rgmii_timing,
-	.port_ops_set_mac_addr = octgmx_rgmii_set_mac_addr,
-	.port_ops_set_filter = octgmx_rgmii_set_filter
+};
+
+struct octgmx_port_ops octgmx_port_ops_sgmii = {
+	.port_ops_enable = octgmx_sgmii_enable,
+	.port_ops_speed = octgmx_sgmii_speed,
+	.port_ops_timing = octgmx_sgmii_timing,
 };
 
 struct octgmx_port_ops octgmx_port_ops_spi42 = {
@@ -143,8 +168,16 @@ struct octgmx_port_ops *octgmx_port_ops[
 	[GMX_MII_PORT] = &octgmx_port_ops_mii,
 	[GMX_GMII_PORT] = &octgmx_port_ops_gmii,
 	[GMX_RGMII_PORT] = &octgmx_port_ops_rgmii,
+	[GMX_SGMII_PORT] = &octgmx_port_ops_sgmii,
 	[GMX_SPI42_PORT] = &octgmx_port_ops_spi42
 };
+static const char *octgmx_port_types[] = {
+	[GMX_MII_PORT] = "MII",
+	[GMX_GMII_PORT] = "GMII",
+	[GMX_RGMII_PORT] = "RGMII",
+	[GMX_SGMII_PORT] = "SGMII",
+	[GMX_SPI42_PORT] = "SPI-4.2"
+};
 
 CFATTACH_DECL_NEW(octgmx, sizeof(struct octgmx_softc),
     octgmx_match, octgmx_attach, NULL, NULL);
@@ -166,10 +199,11 @@ octgmx_attach(device_t parent, device_t 
 {
 	struct octgmx_softc *sc = device_private(self);
 	struct iobus_attach_args *aa = aux;
+	struct octsmi_softc *smi;
+	struct octgmx_port_softc *port_sc;
 	struct octgmx_attach_args gmx_aa;
-	int status;
+	int port, status;
 	int i;
-	struct octgmx_port_softc *port_sc;
 
 	sc->sc_dev = self;
 	sc->sc_regt = aa->aa_bust;
@@ -178,7 +212,7 @@ octgmx_attach(device_t parent, device_t 
 	aprint_normal("\n");
 
 	status = bus_space_map(sc->sc_regt, aa->aa_unit->addr,
-	    GMX0_BASE_IF_SIZE, 0, &sc->sc_regh);
+	    GMX_PORT_SIZE, 0, &sc->sc_regh);
 	if (status != 0)
 		panic(": can't map register");
 
@@ -188,27 +222,54 @@ octgmx_attach(device_t parent, device_t 
 	    M_WAITOK | M_ZERO);
 
 	for (i = 0; i < sc->sc_nports; i++) {
+		port = GMX_PORT_NUM(sc->sc_unitno, i);
+		smi = octsmi_lookup(/*XXX*/0, port);
+		if (smi == NULL)
+			continue;
+
 		port_sc = &sc->sc_ports[i];
 		port_sc->sc_port_gmx = sc;
-		port_sc->sc_port_no = i;
+		port_sc->sc_port_no = port;
 		port_sc->sc_port_type = sc->sc_port_types[i];
 		port_sc->sc_port_ops = octgmx_port_ops[port_sc->sc_port_type];
 		status = bus_space_map(sc->sc_regt,
-		    aa->aa_unit->addr + GMX0_BASE_PORT_SIZE * i,
-		    GMX0_BASE_PORT_SIZE, 0, &port_sc->sc_port_regh);
+		    aa->aa_unit->addr + GMX_PORT_SIZE * i,
+		    GMX_PORT_SIZE, 0, &port_sc->sc_port_regh);
 		if (status != 0)
 			panic(": can't map port register");
 
+		switch (port_sc->sc_port_type) {
+		case GMX_MII_PORT:
+		case GMX_GMII_PORT:
+		case GMX_RGMII_PORT: {
+			struct octasx_attach_args asx_aa;
+
+			asx_aa.aa_port = i;
+			asx_aa.aa_regt = aa->aa_bust;
+			octasx_init(&asx_aa, &port_sc->sc_port_asx);
+			break;
+		}
+		case GMX_SGMII_PORT:
+			if (bus_space_map(sc->sc_regt,
+			    PCS_BASE(sc->sc_unitno, i), PCS_SIZE, 0,
+			    &port_sc->sc_port_pcs_regh))
+				panic("could not map PCS registers");
+			break;
+		default:
+			/* nothing */
+			break;
+		}
+
 		(void)memset(&gmx_aa, 0, sizeof(gmx_aa));
 		gmx_aa.ga_regt = aa->aa_bust;
 		gmx_aa.ga_addr = aa->aa_unit->addr;
 		gmx_aa.ga_name = "cnmac";
-		gmx_aa.ga_portno = i;
+		gmx_aa.ga_portno = port_sc->sc_port_no;
 		gmx_aa.ga_port_type = sc->sc_port_types[i];
+		gmx_aa.ga_smi = smi;
 		gmx_aa.ga_gmx = sc;
 		gmx_aa.ga_gmx_port = port_sc;
-		config_found_sm_loc(self, "octgmx", NULL, &gmx_aa,
-		    octgmx_print, octgmx_submatch);
+		config_found(self, &gmx_aa, octgmx_print);
 	}
 }
 
@@ -216,41 +277,23 @@ static int
 octgmx_print(void *aux, const char *pnp)
 {
 	struct octgmx_attach_args *ga = aux;
-	static const char *types[] = {
-		[GMX_MII_PORT] = "MII",
-		[GMX_GMII_PORT] = "GMII",
-		[GMX_RGMII_PORT] = "RGMII"
-	};
-
-#if DEBUG
-	if (pnp)
-		aprint_normal("%s at %s\n", ga->ga_name, pnp);
-#endif
 
-	aprint_normal(": address=0x%016" PRIx64 ": %s\n", ga->ga_addr,
-	    types[ga->ga_port_type]);
+	aprint_normal(": address=0x%" PRIx64 ": %s\n", ga->ga_addr,
+	    octgmx_port_types[ga->ga_port_type]);
 
 	return UNCONF;
 }
 
 static int
-octgmx_submatch(device_t parent, struct cfdata *cf,
-    const int *ldesc, void *aux)
-{
-	return config_match(parent, cf, aux);
-}
-
-static int
 octgmx_init(struct octgmx_softc *sc)
 {
 	int result = 0;
 	uint64_t inf_mode;
-	/* XXX */
 	const mips_prid_t cpu_id = mips_options.mips_cpu_id;
 
 	inf_mode = bus_space_read_8(sc->sc_regt, sc->sc_regh, GMX0_INF_MODE);
 	if ((inf_mode & INF_MODE_EN) == 0) {
-		aprint_normal("port are disable\n");
+		aprint_normal("ports are disabled\n");
 		sc->sc_nports = 0;
 		return 1;
 	}
@@ -306,6 +349,21 @@ octgmx_init(struct octgmx_softc *sc)
 				sc->sc_nports = 2;
 #endif
 		break;
+	case MIPS_CN70XX:
+		switch (inf_mode & INF_MODE_MODE) {
+		case INF_MODE_MODE_SGMII:
+			sc->sc_nports = 4;
+			for (int i = 0; i < sc->sc_nports; i++)
+				sc->sc_port_types[i] = GMX_SGMII_PORT;
+			break;
+#ifdef notyet
+		case INF_MODE_MODE_XAUI:
+#endif
+		default:
+			sc->sc_nports = 0;
+			result = 1;
+		}
+		break;
 	default:
 		aprint_normal("unsupported octeon model: 0x%x\n", cpu_id); 
 		sc->sc_nports = 0;
@@ -317,7 +375,7 @@ octgmx_init(struct octgmx_softc *sc)
 }
 
 /* XXX RGMII specific */
-int
+static int
 octgmx_link_enable(struct octgmx_port_softc *sc, int enable)
 {
 	uint64_t prt_cfg;
@@ -344,13 +402,13 @@ octgmx_link_enable(struct octgmx_port_so
 int
 octgmx_stats_init(struct octgmx_port_softc *sc)
 {
-        _GMX_PORT_WR8(sc, GMX0_RX0_STATS_PKTS, 0x0ULL);
-        _GMX_PORT_WR8(sc, GMX0_RX0_STATS_PKTS_DRP, 0x0ULL);
-        _GMX_PORT_WR8(sc, GMX0_RX0_STATS_PKTS_BAD, 0x0ULL);
-        _GMX_PORT_WR8(sc, GMX0_TX0_STAT0, 0x0ULL);
-        _GMX_PORT_WR8(sc, GMX0_TX0_STAT1, 0x0ULL);
-        _GMX_PORT_WR8(sc, GMX0_TX0_STAT3, 0x0ULL);
-        _GMX_PORT_WR8(sc, GMX0_TX0_STAT9, 0x0ULL);
+        _GMX_PORT_WR8(sc, GMX0_RX0_STATS_PKTS, 0);
+        _GMX_PORT_WR8(sc, GMX0_RX0_STATS_PKTS_DRP, 0);
+        _GMX_PORT_WR8(sc, GMX0_RX0_STATS_PKTS_BAD, 0);
+        _GMX_PORT_WR8(sc, GMX0_TX0_STAT0, 0);
+        _GMX_PORT_WR8(sc, GMX0_TX0_STAT1, 0);
+        _GMX_PORT_WR8(sc, GMX0_TX0_STAT3, 0);
+        _GMX_PORT_WR8(sc, GMX0_TX0_STAT9, 0);
 
 	return 0;
 }
@@ -358,42 +416,34 @@ octgmx_stats_init(struct octgmx_port_sof
 int
 octgmx_tx_stats_rd_clr(struct octgmx_port_softc *sc, int enable)
 {
-	_GMX_PORT_WR8(sc, GMX0_TX0_STATS_CTL, enable ? 0x1ULL : 0x0ULL);
+	_GMX_PORT_WR8(sc, GMX0_TX0_STATS_CTL, enable ? 1 : 0);
 	return 0;
 }
 
 int
 octgmx_rx_stats_rd_clr(struct octgmx_port_softc *sc, int enable)
 {
-	_GMX_PORT_WR8(sc, GMX0_RX0_STATS_CTL, enable ? 0x1ULL : 0x0ULL);
+	_GMX_PORT_WR8(sc, GMX0_RX0_STATS_CTL, enable ? 1 : 0);
 	return 0;
 }
 
-void
-octgmx_rx_stats_dec_bad(struct octgmx_port_softc *sc)
-{
-	uint64_t tmp;
-
-        tmp = _GMX_PORT_RD8(sc, GMX0_RX0_STATS_PKTS_BAD);
-	_GMX_PORT_WR8(sc, GMX0_RX0_STATS_PKTS_BAD, tmp - 1);
-}
-
 static int
 octgmx_tx_ovr_bp_enable(struct octgmx_port_softc *sc, int enable)
 {
 	uint64_t ovr_bp;
+	int index = GMX_PORT_INDEX(sc->sc_port_no);
 
 	ovr_bp = _GMX_RD8(sc, GMX0_TX_OVR_BP);
 	if (enable) {
-		CLR(ovr_bp, __SHIFTIN(__BIT(sc->sc_port_no), TX_OVR_BP_EN));
-		SET(ovr_bp, __SHIFTIN(__BIT(sc->sc_port_no), TX_OVR_BP_BP));
+		CLR(ovr_bp, __SHIFTIN(__BIT(index), TX_OVR_BP_EN));
+		SET(ovr_bp, __SHIFTIN(__BIT(index), TX_OVR_BP_BP));
 		/* XXX really??? */
-		SET(ovr_bp, __SHIFTIN(__BIT(sc->sc_port_no), TX_OVR_BP_IGN_FULL));
+		SET(ovr_bp, __SHIFTIN(__BIT(index), TX_OVR_BP_IGN_FULL));
 	} else {
-		SET(ovr_bp, __SHIFTIN(__BIT(sc->sc_port_no), TX_OVR_BP_EN));
-		CLR(ovr_bp, __SHIFTIN(__BIT(sc->sc_port_no), TX_OVR_BP_BP));
+		SET(ovr_bp, __SHIFTIN(__BIT(index), TX_OVR_BP_EN));
+		CLR(ovr_bp, __SHIFTIN(__BIT(index), TX_OVR_BP_BP));
 		/* XXX really??? */
-		SET(ovr_bp, __SHIFTIN(__BIT(sc->sc_port_no), TX_OVR_BP_IGN_FULL));
+		SET(ovr_bp, __SHIFTIN(__BIT(index), TX_OVR_BP_IGN_FULL));
 	}
 	_GMX_WR8(sc, GMX0_TX_OVR_BP, ovr_bp);
 	return 0;
@@ -411,7 +461,7 @@ octgmx_rx_pause_enable(struct octgmx_por
 	return 0;
 }
 
-void
+static void
 octgmx_tx_int_enable(struct octgmx_port_softc *sc, int enable)
 {
 	uint64_t tx_int_xxx = 0;
@@ -426,7 +476,7 @@ octgmx_tx_int_enable(struct octgmx_port_
 	_GMX_WR8(sc, GMX0_TX_INT_EN, enable ? tx_int_xxx : 0);
 }
 
-void
+static void
 octgmx_rx_int_enable(struct octgmx_port_softc *sc, int enable)
 {
 	uint64_t rx_int_xxx = 0;
@@ -455,21 +505,20 @@ octgmx_rx_int_enable(struct octgmx_port_
 	_GMX_PORT_WR8(sc, GMX0_RX0_INT_EN, enable ? rx_int_xxx : 0);
 }
 
-int
+static int
 octgmx_rx_frm_ctl_enable(struct octgmx_port_softc *sc, uint64_t rx_frm_ctl)
 {
-	/*
-	 * XXX Jumbo-frame Workarounds
-	 *     Current implementation of cnmac is required to
-	 *     configure GMX0_RX0_JABBER[CNT] as follows:
-	 *	RX0_FRM_MAX(1536) <= GMX0_RX0_JABBER <= 1536(0x600)
-	 */
-	_GMX_PORT_WR8(sc, GMX0_RX0_JABBER, GMX_FRM_MAX_SIZ);
+	struct ifnet *ifp = &sc->sc_port_ec->ec_if;
+	unsigned int maxlen;
+
+	maxlen = roundup(ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN +
+	    ETHER_VLAN_ENCAP_LEN, 8);
+	_GMX_PORT_WR8(sc, GMX0_RX0_JABBER, maxlen);
 
 	return octgmx_rx_frm_ctl_xable(sc, rx_frm_ctl, 1);
 }
 
-int
+static int
 octgmx_rx_frm_ctl_disable(struct octgmx_port_softc *sc, uint64_t rx_frm_ctl)
 {
 	return octgmx_rx_frm_ctl_xable(sc, rx_frm_ctl, 0);
@@ -491,7 +540,7 @@ octgmx_rx_frm_ctl_xable(struct octgmx_po
 	return 0;
 }
 
-int
+static int
 octgmx_tx_thresh(struct octgmx_port_softc *sc, int cnt)
 {
 	_GMX_PORT_WR8(sc, GMX0_TX0_THRESH, cnt);
@@ -499,19 +548,145 @@ octgmx_tx_thresh(struct octgmx_port_soft
 }
 
 int
-octgmx_set_mac_addr(struct octgmx_port_softc *sc, uint8_t *addr)
+octgmx_set_mac_addr(struct octgmx_port_softc *sc, const uint8_t *addr)
 {
-	uint64_t mac = 0;
+	uint64_t mac;
+	int i;
 
 	ADDR2UINT64(mac, addr);
-	(*sc->sc_port_ops->port_ops_set_mac_addr)(sc, addr, mac);
+
+	octgmx_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, octgmx_rx_adr_cam_regs[i], addr[i]);
+
+	octgmx_link_enable(sc, 1);
+
 	return 0;
 }
 
 int
 octgmx_set_filter(struct octgmx_port_softc *sc)
 {
-	(*sc->sc_port_ops->port_ops_set_filter)(sc);
+	struct ethercom *ec = sc->sc_port_ec;
+	struct ifnet *ifp = &ec->ec_if;
+	struct ether_multi *enm;
+	struct ether_multistep step;
+	uint64_t ctl = 0;
+	int multi = 0;
+	uint64_t cam_en = 1;	/* enable CAM 0 for self MAC addr */
+
+	octgmx_link_enable(sc, 0);
+
+	if (ISSET(ifp->if_flags, IFF_BROADCAST)) {
+		dprintf("accept broadcast\n");
+		SET(ctl, RXN_ADR_CTL_BCST);
+	}
+	if (ISSET(ifp->if_flags, IFF_PROMISC)) {
+		dprintf("promiscas(reject cam)\n");
+		CLR(ctl, RXN_ADR_CTL_CAM_MODE);
+	} else {
+		dprintf("not promiscas(accept cam)\n");
+		SET(ctl, RXN_ADR_CTL_CAM_MODE);
+	}
+
+	/*
+	 * Note first entry is self MAC address; other 7 entires are available
+	 * for multicast addresses.
+	 */
+
+	ETHER_LOCK(ec);
+	ETHER_FIRST_MULTI(step, ec, enm);
+	while (enm != NULL) {
+		int i;
+
+		dprintf("%d: lo(%02x:%02x:%02x:%02x:%02x:%02x) - "
+		    "hi(%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],
+		    enm->enm_addrhi[0], enm->enm_addrhi[1],
+		    enm->enm_addrhi[2], enm->enm_addrhi[3],
+		    enm->enm_addrhi[4], enm->enm_addrhi[5]);
+		if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
+			dprintf("all multicast\n");
+			SET(ifp->if_flags, IFF_ALLMULTI);
+			ETHER_UNLOCK(ec);
+			goto setmulti;
+		}
+		multi++;
+
+		/* XXX XXX XXX */
+		if (multi >= 8) {
+			SET(ifp->if_flags, IFF_ALLMULTI);
+			ETHER_UNLOCK(ec);
+			goto setmulti;
+		}
+		/* XXX XXX XXX */
+
+		/* XXX XXX XXX */
+		SET(cam_en, __BIT(multi));
+		/* XXX XXX XXX */
+
+		for (i = 0; i < 6; i++) {
+			uint64_t tmp;
+
+			/* XXX XXX XXX */
+			tmp = _GMX_PORT_RD8(sc, octgmx_rx_adr_cam_regs[i]);
+			CLR(tmp, 0xffULL << (8 * multi));
+			SET(tmp, (uint64_t)enm->enm_addrlo[i] << (8 * multi));
+			_GMX_PORT_WR8(sc, octgmx_rx_adr_cam_regs[i], tmp);
+			/* XXX XXX XXX */
+			    
+		}
+		for (i = 0; i < 6; i++)
+			dprintf("cam%d = 0x%016lx\n", i,
+			    _GMX_PORT_RD8(sc, octgmx_rx_adr_cam_regs[i]));
+		ETHER_NEXT_MULTI(step, enm);
+	}
+	ETHER_UNLOCK(ec);
+	CLR(ifp->if_flags, IFF_ALLMULTI);
+
+	CNMAC_KASSERT(enm == NULL);
+
+setmulti:
+	/* XXX XXX XXX */
+	if (ISSET(ifp->if_flags, IFF_ALLMULTI) ||
+	    ISSET(ifp->if_flags, IFF_PROMISC)) {
+		/* XXX XXX XXX */
+		dprintf("accept all multicast\n");
+		ctl |= __SHIFTIN(RXN_ADR_CTL_MCST_ACCEPT, RXN_ADR_CTL_MCST);
+		/* XXX XXX XXX */
+	} else if (multi) {
+		/* XXX XXX XXX */
+		dprintf("use cam\n");
+		ctl |= __SHIFTIN(RXN_ADR_CTL_MCST_AFCAM, RXN_ADR_CTL_MCST);
+		/* XXX XXX XXX */
+	} else {
+		/* XXX XXX XXX */
+		dprintf("reject all multicast\n");
+		ctl |= __SHIFTIN(RXN_ADR_CTL_MCST_REJECT, RXN_ADR_CTL_MCST);
+		/* XXX XXX XXX */
+	}
+	/* XXX XXX XXX */
+
+	/* XXX XXX XXX */
+	if (ISSET(ifp->if_flags, IFF_PROMISC)) {
+		cam_en = 0x00ULL;
+	} else if (ISSET(ifp->if_flags, IFF_ALLMULTI)) {
+		cam_en = 0x01ULL;
+	}
+	/* XXX XXX XXX */
+
+	dprintf("ctl = %#lx, cam_en = %#lx\n", ctl, cam_en);
+	_GMX_PORT_WR8(sc, GMX0_RX0_ADR_CTL, ctl);
+	_GMX_PORT_WR8(sc, GMX0_RX0_ADR_CAM_EN, cam_en);
+
+	octgmx_link_enable(sc, 1);
+
 	return 0;
 }
 
@@ -623,8 +798,6 @@ octgmx_rgmii_speed(struct octgmx_port_so
 	}
 	ifp->if_baudrate = baudrate;
 
-	/* XXX XXX XXX */
-
 	octgmx_link_enable(sc, 0);
 
 	/*
@@ -644,30 +817,10 @@ octgmx_rgmii_speed(struct octgmx_port_so
 static int
 octgmx_rgmii_speed_newlink(struct octgmx_port_softc *sc, uint64_t *rnewlink)
 {
-	uint64_t newlink = 0;
+	uint64_t newlink;
 
-	if (sc->sc_quirks & CNMAC_QUIRKS_NO_RX_INBND) {
-		newlink = 0;
-		switch (IFM_SUBTYPE(sc->sc_port_mii->mii_media_active)) {
-		default:
-			SET(newlink, RXN_RX_INBND_SPEED_125);
-			break;
-		case IFM_100_TX:
-			SET(newlink, RXN_RX_INBND_SPEED_25);
-			break;
-		case IFM_10_T:
-			SET(newlink, RXN_RX_INBND_SPEED_2_5);
-			break;
-		}
-		SET(newlink,
-		    ISSET(sc->sc_port_mii->mii_media_active, IFM_FDX) ?
-		    RXN_RX_INBND_DUPLEX : 0);
-		SET(newlink,
-		    ISSET(sc->sc_port_mii->mii_media_status, IFM_ACTIVE) ?
-		    RXN_RX_INBND_STATUS : 0);
-	} else {
-		newlink = _GMX_PORT_RD8(sc, GMX0_RX0_RX_INBND);
-	}
+	/* Inband status does not seem to work */
+	newlink = _GMX_PORT_RD8(sc, GMX0_RX0_RX_INBND);
 
 	*rnewlink = newlink;
 	return 0;
@@ -833,8 +986,6 @@ octgmx_rgmii_timing(struct octgmx_port_s
 	    RXN_FRM_CTL_CTL_DRP |
 	    RXN_FRM_CTL_PRE_STRP |
 	    RXN_FRM_CTL_PRE_CHK;
-	if (!(sc->sc_quirks & CNMAC_QUIRKS_NO_PRE_ALIGN))
-		rx_frm_ctl |= RXN_FRM_CTL_PRE_ALIGN;
 	octgmx_rx_frm_ctl_enable(sc, rx_frm_ctl);
 
 	/* RGMII RX Clock-Delay Registers
@@ -855,158 +1006,148 @@ octgmx_rgmii_timing(struct octgmx_port_s
 }
 
 static int
-octgmx_rgmii_set_mac_addr(struct octgmx_port_softc *sc, uint8_t *addr,
-    uint64_t mac)
+octgmx_sgmii_enable(struct octgmx_port_softc *sc, int enable)
 {
+	uint64_t ctl_reg, status, timer_count;
+	uint64_t cpu_freq_mhz = curcpu()->ci_cpu_freq / 1000000;
+	int done;
 	int i;
 
-	octgmx_link_enable(sc, 0);
+	if (!enable)
+		return 0;
 
-	sc->sc_mac = mac;
-	_GMX_PORT_WR8(sc, GMX0_SMAC0, mac);
-	for (i = 0; i < 6; i++)
-		_GMX_PORT_WR8(sc, octgmx_rx_adr_cam_regs[i], addr[i]);
+	/* Set link timer interval to 1.6ms.  Timer multiple is 1024 (2^10). */
+	/*
+	 * XXX Should set timer to 10ms if not in SGMII mode (ie,
+	 * "cavium,sgmii-mac-1000x-mode" property exists
+	 */
+	timer_count = PCS_READ_8(sc, PCS_LINK_TIMER_COUNT);
+	CLR(timer_count, PCS_LINK_TIMER_COUNT_MASK);
+	SET(timer_count,
+	    __SHIFTIN((1600 * cpu_freq_mhz) >> 10, PCS_LINK_TIMER_COUNT_MASK));
+	PCS_WRITE_8(sc, PCS_LINK_TIMER_COUNT, timer_count);
+
+	/* Reset the PCS. */
+	ctl_reg = PCS_READ_8(sc, PCS_MR_CONTROL);
+	SET(ctl_reg, PCS_MR_CONTROL_RESET);
+	PCS_WRITE_8(sc, PCS_MR_CONTROL, ctl_reg);
+
+	/* Wait for the reset to complete. */
+	done = 0;
+	for (i = 0; i < 1000000; i++) {
+		ctl_reg = PCS_READ_8(sc, PCS_MR_CONTROL);
+		if (!ISSET(ctl_reg, PCS_MR_CONTROL_RESET)) {
+			done = 1;
+			break;
+		}
+	}
+	if (!done) {
+		printf("SGMII reset timeout on port %d\n", sc->sc_port_no);
+		return 1;
+	}
 
-	octgmx_link_enable(sc, 1);
+	/* Start a new SGMII autonegotiation. */
+	SET(ctl_reg, PCS_MR_CONTROL_AN_EN);
+	SET(ctl_reg, PCS_MR_CONTROL_RST_AN);
+	CLR(ctl_reg, PCS_MR_CONTROL_PWR_DN);
+	PCS_WRITE_8(sc, PCS_MR_CONTROL, ctl_reg);
+
+	/* Wait for the SGMII autonegotiation to complete. */
+	done = 0;
+	for (i = 0; i < 1000000; i++) {
+		status = PCS_READ_8(sc, PCS_MR_STATUS);
+		if (ISSET(status, PCS_MR_STATUS_AN_CPT)) {
+			done = 1;
+			break;
+		}
+	}
+	if (!done) {
+		printf("SGMII autonegotiation timeout on port %d\n",
+		    sc->sc_port_no);
+		return 1;
+	}
 
 	return 0;
 }
 
-#define	CNMAC_USE_GMX_CAM
-
 static int
-octgmx_rgmii_set_filter(struct octgmx_port_softc *sc)
+octgmx_sgmii_speed(struct octgmx_port_softc *sc)
 {
-	struct ethercom *ec = sc->sc_port_ec;
-	struct ifnet *ifp = &ec->ec_if;
-#ifdef CNMAC_USE_GMX_CAM
-	struct ether_multi *enm;
-	struct ether_multistep step;
-#endif
-	uint64_t ctl = 0;
-	int multi = 0;
-	/* XXX XXX XXX */
-	uint64_t cam_en = 0x01ULL;
-	/* XXX XXX XXX */
+	uint64_t misc_ctl, prt_cfg;
+	int tx_burst, tx_slot;
 
 	octgmx_link_enable(sc, 0);
 
-	if (ISSET(ifp->if_flags, IFF_BROADCAST)) {
-		dprintf("accept broadcast\n");
-		SET(ctl, RXN_ADR_CTL_BCST);
-	}
-	if (ISSET(ifp->if_flags, IFF_PROMISC)) {
-		dprintf("promiscas(reject cam)\n");
-		CLR(ctl, RXN_ADR_CTL_CAM_MODE);
-	} else {
-		dprintf("not promiscas(accept cam)\n");
-		SET(ctl, RXN_ADR_CTL_CAM_MODE);
-	}
-
-#ifdef CNMAC_USE_GMX_CAM
-	/*
-	 * Note first entry is self MAC address; other 7 entires are available
-	 * for multicast addresses.
-	 */
+	prt_cfg = _GMX_PORT_RD8(sc, GMX0_PRT0_CFG);
 
-	ETHER_LOCK(ec);
-	ETHER_FIRST_MULTI(step, ec, enm);
-	while (enm != NULL) {
-		int i;
+	if (ISSET(sc->sc_port_mii->mii_media_active, IFM_FDX))
+		SET(prt_cfg, PRTN_CFG_DUPLEX);
+	else
+		CLR(prt_cfg, PRTN_CFG_DUPLEX);
 
-		dprintf("%d: lo(%02x:%02x:%02x:%02x:%02x:%02x) - "
-		    "hi(%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],
-		    enm->enm_addrhi[0], enm->enm_addrhi[1],
-		    enm->enm_addrhi[2], enm->enm_addrhi[3],
-		    enm->enm_addrhi[4], enm->enm_addrhi[5]);
-		if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
-			dprintf("all multicast\n");
-			SET(ifp->if_flags, IFF_ALLMULTI);
-			ETHER_UNLOCK(ec);
-			goto setmulti;
-		}
-		multi++;
+	misc_ctl = PCS_READ_8(sc, PCS_MISC_CTL);
+	CLR(misc_ctl, PCS_MISC_CTL_SAMP_PT);
 
-		/* XXX XXX XXX */
-		if (multi >= 8) {
-			SET(ifp->if_flags, IFF_ALLMULTI);
-			ETHER_UNLOCK(ec);
-			goto setmulti;
-		}
-		/* XXX XXX XXX */
+	/* Disable the GMX port if the link is down. */
+	if (octgmx_link_status(sc))
+		CLR(misc_ctl, PCS_MISC_CTL_GMXENO);
+	else
+		SET(misc_ctl, PCS_MISC_CTL_GMXENO);
 
-		/* XXX XXX XXX */
-		SET(cam_en, __BIT(multi));
-		/* XXX XXX XXX */
+	switch (sc->sc_port_ec->ec_if.if_baudrate) {
+	case IF_Mbps(10):
+		tx_slot = 0x40;
+		tx_burst = 0;
+		CLR(prt_cfg, PRTN_CFG_SPEED);
+		SET(prt_cfg, PRTN_CFG_SPEED_MSB);
+		CLR(prt_cfg, PRTN_CFG_SLOTTIME);
+		misc_ctl |= 25 & PCS_MISC_CTL_SAMP_PT;
+		break;
+	case IF_Mbps(100):
+		tx_slot = 0x40;
+		tx_burst = 0;
+		CLR(prt_cfg, PRTN_CFG_SPEED);
+		CLR(prt_cfg, PRTN_CFG_SPEED_MSB);
+		CLR(prt_cfg, PRTN_CFG_SLOTTIME);
+		misc_ctl |= 5 & PCS_MISC_CTL_SAMP_PT;
+		break;
+	case IF_Gbps(1):
+	default:
+		tx_slot = 0x200;
+		tx_burst = 0x2000;
+		SET(prt_cfg, PRTN_CFG_SPEED);
+		CLR(prt_cfg, PRTN_CFG_SPEED_MSB);
+		SET(prt_cfg, PRTN_CFG_SLOTTIME);
+		misc_ctl |= 1 & PCS_MISC_CTL_SAMP_PT;
+		break;
+	}
 
-		for (i = 0; i < 6; i++) {
-			uint64_t tmp;
+	PCS_WRITE_8(sc, PCS_MISC_CTL, misc_ctl);
 
-			/* XXX XXX XXX */
-			tmp = _GMX_PORT_RD8(sc, octgmx_rx_adr_cam_regs[i]);
-			CLR(tmp, 0xffULL << (8 * multi));
-			SET(tmp, (uint64_t)enm->enm_addrlo[i] << (8 * multi));
-			_GMX_PORT_WR8(sc, octgmx_rx_adr_cam_regs[i], tmp);
-			/* XXX XXX XXX */
-			    
-		}
-		for (i = 0; i < 6; i++)
-			dprintf("cam%d = %016llx\n", i,
-			    _GMX_PORT_RD8(sc, octgmx_rx_adr_cam_regs[i]));
-		ETHER_NEXT_MULTI(step, enm);
-	}
-	ETHER_UNLOCK(ec);
-	CLR(ifp->if_flags, IFF_ALLMULTI);
+	_GMX_PORT_WR8(sc, GMX0_TX0_SLOT, tx_slot);
+	_GMX_PORT_WR8(sc, GMX0_TX0_BURST, tx_burst);
+	_GMX_PORT_WR8(sc, GMX0_PRT0_CFG, prt_cfg);
 
-	CNMAC_KASSERT(enm == NULL);
-#else
-	/*
-	 * XXX
-	 * Never use DMAC filter for multicast addresses, but register only
-	 * single entry for self address. FreeBSD code do so.
-	 */
-	SET(ifp->if_flags, IFF_ALLMULTI);
-	goto setmulti;
-#endif
+	octgmx_link_enable(sc, 1);
 
-setmulti:
-	/* XXX XXX XXX */
-	if (ISSET(ifp->if_flags, IFF_ALLMULTI) ||
-	    ISSET(ifp->if_flags, IFF_PROMISC)) {
-		/* XXX XXX XXX */
-		dprintf("accept all multicast\n");
-		ctl |= __SHIFTIN(RXN_ADR_CTL_MCST_ACCEPT, RXN_ADR_CTL_MCST);
-		/* XXX XXX XXX */
-	} else if (multi) {
-		/* XXX XXX XXX */
-		dprintf("use cam\n");
-		ctl |= __SHIFTIN(RXN_ADR_CTL_MCST_AFCAM, RXN_ADR_CTL_MCST);
-		/* XXX XXX XXX */
-	} else {
-		/* XXX XXX XXX */
-		dprintf("reject all multicast\n");
-		ctl |= __SHIFTIN(RXN_ADR_CTL_MCST_REJECT, RXN_ADR_CTL_MCST);
-		/* XXX XXX XXX */
-	}
-	/* XXX XXX XXX */
+	return 0;
+}
 
-	/* XXX XXX XXX */
-	if (ISSET(ifp->if_flags, IFF_PROMISC)) {
-		cam_en = 0x00ULL;
-	} else if (ISSET(ifp->if_flags, IFF_ALLMULTI)) {
-		cam_en = 0x01ULL;
-	}
-	/* XXX XXX XXX */
+static int
+octgmx_sgmii_timing(struct octgmx_port_softc *sc)
+{
+	uint64_t rx_frm_ctl;
 
-	dprintf("ctl = %llx, cam_en = %llx\n", ctl, cam_en);
-	_GMX_PORT_WR8(sc, GMX0_RX0_ADR_CTL, ctl);
-	_GMX_PORT_WR8(sc, GMX0_RX0_ADR_CAM_EN, cam_en);
+	octgmx_tx_thresh(sc, 32);
 
-	octgmx_link_enable(sc, 1);
+	rx_frm_ctl =
+	    RXN_FRM_CTL_PRE_FREE |
+	    RXN_FRM_CTL_CTL_SMAC |
+	    RXN_FRM_CTL_CTL_MCST |
+	    RXN_FRM_CTL_CTL_DRP |
+	    RXN_FRM_CTL_PRE_STRP |
+	    RXN_FRM_CTL_PRE_CHK;
+	octgmx_rx_frm_ctl_enable(sc, rx_frm_ctl);
 
 	return 0;
 }
@@ -1045,98 +1186,3 @@ octgmx_stats(struct octgmx_port_softc *s
 	if_statadd_ref(nsr, if_oerrors, (uint32_t)(tmp >> 32));
 	IF_STAT_PUTREF(ifp);
 }
-
-/* ---- DMAC filter */
-
-#ifdef notyet
-/*
- * DMAC filter configuration
- *	accept all
- *	reject 0 addrs (virtually accept all?)
- *	reject N addrs
- *	accept N addrs
- *	accept 0 addrs (virtually reject all?)
- *	reject all
- */
-
-/* XXX local namespace */
-#define	_POLICY			OCTEON_GMX_FILTER_POLICY
-#define	_POLICY_ACCEPT_ALL	OCTEON_GMX_FILTER_POLICY_ACCEPT_ALL
-#define	_POLICY_ACCEPT		OCTEON_GMX_FILTER_POLICY_ACCEPT
-#define	_POLICY_REJECT		OCTEON_GMX_FILTER_POLICY_REJECT
-#define	_POLICY_REJECT_ALL	OCTEON_GMX_FILTER_POLICY_REJECT_ALL
-
-static int	octgmx_setfilt_addrs(struct octgmx_port_softc *, size_t,
-		    uint8_t **);
-
-int
-octgmx_setfilt(struct octgmx_port_softc *sc, enum _POLICY policy, size_t naddrs,
-    uint8_t **addrs)
-{
-	uint64_t rx_adr_ctl;
-
-	KASSERT(policy >= _POLICY_ACCEPT_ALL);
-	KASSERT(policy <= _POLICY_REJECT_ALL);
-
-	rx_adr_ctl = _GMX_PORT_RD8(sc, GMX0_RX0_ADR_CTL);
-	CLR(rx_adr_ctl, RXN_ADR_CTL_CAM_MODE | RXN_ADR_CTL_MCST);
-
-	switch (policy) {
-	case _POLICY_ACCEPT_ALL:
-	case _POLICY_REJECT_ALL:
-		KASSERT(naddrs == 0);
-		KASSERT(addrs == NULL);
-
-		SET(rx_adr_ctl,
-		    __SHIFTIN((policy == _POLICY_ACCEPT_ALL) ?
-		      RXN_ADR_CTL_MCST_ACCEPT : RXN_ADR_CTL_MCST_REJECT),
-		    RXN_ADR_CTL_MCST);
-		break;
-	case _POLICY_ACCEPT:
-	case _POLICY_REJECT:
-		if (naddrs > OCTEON_GMX_FILTER_NADDRS_MAX)
-			return E2BIG;
-		SET(rx_adr_ctl, (policy == _POLICY_ACCEPT) ?
-		    RXN_ADR_CTL_CAM_MODE : 0);
-		SET(rx_adr_ctl,
-		    __SHIFTIN(RXN_ADR_CTL_MCST_AFCAM, RXN_ADR_CTL_MCST);
-		/* set GMX0_RXN_ADR_CAM_EN, GMX0_RXN_ADR_CAM[0-5] */
-		octgmx_setfilt_addrs(sc, naddrs, addrs);
-		break;
-	}
-
-	/* set GMX0_RXN_ADR_CTL[MCST] */
-	_GMX_PORT_WR8(sc, GMX0_RX0_ADR_CTL, rx_adr_ctl);
-
-	return 0;
-}
-
-static int
-octgmx_setfilt_addrs(struct octgmx_port_softc *sc, size_t naddrs,
-    uint8_t **addrs)
-{
-	uint64_t rx_adr_cam_en;
-	uint64_t rx_adr_cam_addrs[OCTEON_GMX_FILTER_NADDRS_MAX];
-	int i, j;
-
-	KASSERT(naddrs <= OCTEON_GMX_FILTER_NADDRS_MAX);
-
-	rx_adr_cam_en = 0;
-	(void)memset(rx_adr_cam_addrs, 0, sizeof(rx_adr_cam_addrs));
-
-	for (i = 0; i < naddrs; i++) {
-		SET(rx_adr_cam_en, __BIT(i));
-		for (j = 0; j < 6; j++)
-			SET(rx_adr_cam_addrs[j],
-			    (uint64_t)addrs[i][j] << (8 * i));
-	}
-
-	/* set GMX0_RXN_ADR_CAM_EN, GMX0_RXN_ADR_CAM[0-5] */
-	_GMX_PORT_WR8(sc, GMX0_RX0_ADR_CAM_EN, rx_adr_cam_en);
-	for (j = 0; j < 6; j++)
-		_GMX_PORT_WR8(sc, octgmx_rx_adr_cam_regs[j],
-		    rx_adr_cam_addrs[j]);
-
-	return 0;
-}
-#endif

Index: src/sys/arch/mips/cavium/dev/octeon_gmxreg.h
diff -u src/sys/arch/mips/cavium/dev/octeon_gmxreg.h:1.4 src/sys/arch/mips/cavium/dev/octeon_gmxreg.h:1.5
--- src/sys/arch/mips/cavium/dev/octeon_gmxreg.h:1.4	Mon Jun 22 12:26:11 2020
+++ src/sys/arch/mips/cavium/dev/octeon_gmxreg.h	Tue Jun 23 05:17:13 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: octeon_gmxreg.h,v 1.4 2020/06/22 12:26:11 simonb Exp $	*/
+/*	$NetBSD: octeon_gmxreg.h,v 1.5 2020/06/23 05:17:13 simonb Exp $	*/
 
 /*
  * Copyright (c) 2007 Internet Initiative Japan, Inc.
@@ -169,7 +169,9 @@
 
 /* GMX Port Configuration Registers */
 
-#define	PRTN_CFG_XXX_63_4			UINT64_C(0xfffffffffffffff0)
+#define	PRTN_CFG_XXX_63_9			UINT64_C(0xfffffffffffffe00)
+#define	PRTN_CFG_SPEED_MSB			UINT64_C(0x0000000000000100)
+#define	PRTN_CFG_XXX_7_4			UINT64_C(0x00000000000000f0)
 #define	PRTN_CFG_SLOTTIME			UINT64_C(0x0000000000000008)
 #define	PRTN_CFG_DUPLEX				UINT64_C(0x0000000000000004)
 #define	PRTN_CFG_SPEED				UINT64_C(0x0000000000000002)
@@ -611,19 +613,87 @@
 #define	INF_MODE_P0MII				UINT64_C(0x0000000000000004)
 #define	INF_MODE_EN				UINT64_C(0x0000000000000002)
 #define	INF_MODE_TYPE				UINT64_C(0x0000000000000001)
+/* Interface mode, applicable on CN68xx and CN7xxx (?) */
+#define	INF_MODE_MODE				UINT64_C(0x0000000000000070)
+#define	INF_MODE_MODE_SGMII			UINT64_C(0x0000000000000020)
+#define	INF_MODE_MODE_XAUI			UINT64_C(0x0000000000000030)
+
+#define	MIO_QLM_CFG(x)				(UINT64_C(0x0001180000001590) + (x)*8)
+
+#define	MIO_QLM_CFG_CFG				UINT64_C(0x000000000000000f)
 
 /* -------------------------------------------------------------------------- */
 
 /* for bus_space(9) */
 
-#define GMX_IF_NUNITS				1
-#define GMX_PORT_NUNITS				3
+#define	GMX_PORT_NUNITS				(5 * 16)
+#define	GMX_PORT_NUM(g, i)			((g) * 16 + (i))
+#define	GMX_PORT_IFACE(port)			((port) / 16)
+#define	GMX_PORT_INDEX(port)			((port) % 16)
+
+#define	GMX_BLOCK_SIZE				0x8000000
+#define	GMX_CN68XX_BLOCK_SIZE			0x100000 /* different on CN68XX only */
+
+#define	GMX0_BASE_PORT0				UINT64_C(0x0001180008000000)
+#define	GMX_PORT_SIZE				0x800
+#define	GMX_IF_SIZE(n)				(GMX_PORT_SIZE * (n))
+#define	GMX_BASE_PORT(n, m) 		/* address of GMX(n) * PORT(m) */ \
+	(GMX0_BASE_PORT0 + (n) * GMX_BLOCK_SIZE + GMX_IF_SIZE(m))
+#define	GMX_CN68XX_BASE_PORT(n, m) 	/* address of GMX(n) * PORT(m) */ \
+	(GMX0_BASE_PORT0 + (n) * GMX_CN68XX_BLOCK_SIZE + GMX_IF_SIZE(m))
+
+/* -------------------------------------------------------------------------- */
+
+/* Low-level SGMII link controll */
+
+#define	PCS_BASE(g, i)	(UINT64_C(0x00011800b0001000) + 0x8000000 * (g) + 0x400 * (i))
+#define	PCS_SIZE	0x98
 
-#define	GMX0_BASE_PORT0				0x0001180008000000ULL
-#define	GMX0_BASE_PORT1				0x0001180008000800ULL
-#define	GMX0_BASE_PORT2				0x0001180008001000ULL
-#define	GMX0_BASE_PORT_SIZE				0x00800
-#define	GMX0_BASE_IF0				0x0001180008000000ULL
-#define	GMX0_BASE_IF_SIZE			(GMX0_BASE_PORT_SIZE * GMX_PORT_NUNITS)
+#define	PCS_MR_CONTROL				0x00
+#define	PCS_MR_STATUS				0x08
+#define	PCS_LINK_TIMER_COUNT			0x40
+#define	PCS_MISC_CTL				0x78
+
+#define	PCS_MR_CONTROL_RES_16_63		UINT64_C(0xffffffffffff0000)
+#define	PCS_MR_CONTROL_RESET			UINT64_C(0x0000000000008000)
+#define	PCS_MR_CONTROL_LOOPBCK1			UINT64_C(0x0000000000004000)
+#define	PCS_MR_CONTROL_SPDLSB			UINT64_C(0x0000000000002000)
+#define	PCS_MR_CONTROL_AN_EN			UINT64_C(0x0000000000001000)
+#define	PCS_MR_CONTROL_PWR_DN			UINT64_C(0x0000000000000800)
+#define	PCS_MR_CONTROL_RES_10_10		UINT64_C(0x0000000000000400)
+#define	PCS_MR_CONTROL_RST_AN			UINT64_C(0x0000000000000200)
+#define	PCS_MR_CONTROL_DUPLEX			UINT64_C(0x0000000000000100)
+#define	PCS_MR_CONTROL_COLTST			UINT64_C(0x0000000000000080)
+#define	PCS_MR_CONTROL_SPDMSB			UINT64_C(0x0000000000000040)
+#define	PCS_MR_CONTROL_UNI			UINT64_C(0x0000000000000020)
+#define	PCS_MR_CONTROL_RES_0_4			UINT64_C(0x000000000000001f)
+
+#define	PCS_MR_STATUS_RES_16_63			UINT64_C(0xffffffffffff0000)
+#define	PCS_MR_STATUS_HUN_T4			UINT64_C(0x0000000000008000)
+#define	PCS_MR_STATUS_HUN_XFD			UINT64_C(0x0000000000004000)
+#define	PCS_MR_STATUS_HUN_XHD			UINT64_C(0x0000000000002000)
+#define	PCS_MR_STATUS_TEN_FD			UINT64_C(0x0000000000001000)
+#define	PCS_MR_STATUS_TEN_HD			UINT64_C(0x0000000000000800)
+#define	PCS_MR_STATUS_HUN_T2FD			UINT64_C(0x0000000000000400)
+#define	PCS_MR_STATUS_HUN_T2HD			UINT64_C(0x0000000000000200)
+#define	PCS_MR_STATUS_EXT_ST			UINT64_C(0x0000000000000100)
+#define	PCS_MR_STATUS_RES_7_7			UINT64_C(0x0000000000000080)
+#define	PCS_MR_STATUS_PRB_SUP			UINT64_C(0x0000000000000040)
+#define	PCS_MR_STATUS_AN_CPT			UINT64_C(0x0000000000000020)
+#define	PCS_MR_STATUS_RM_FLT			UINT64_C(0x0000000000000010)
+#define	PCS_MR_STATUS_AN_ABIL			UINT64_C(0x0000000000000008)
+#define	PCS_MR_STATUS_LNK_ST			UINT64_C(0x0000000000000004)
+#define	PCS_MR_STATUS_RES_1_1			UINT64_C(0x0000000000000002)
+#define	PCS_MR_STATUS_EXTND			UINT64_C(0x0000000000000001)
+
+#define	PCS_LINK_TIMER_COUNT_MASK		UINT64_C(0x000000000000ffff)
+
+#define	PCS_MISC_CTL_SGMII			UINT64_C(0x0000000000001000)
+#define	PCS_MISC_CTL_GMXENO			UINT64_C(0x0000000000000800)
+#define	PCS_MISC_CTL_LOOPBCK2			UINT64_C(0x0000000000000400)
+#define	PCS_MISC_CTL_MAC_PHY			UINT64_C(0x0000000000000200)
+#define	PCS_MISC_CTL_MODE			UINT64_C(0x0000000000000100)
+#define	PCS_MISC_CTL_AN_OVRD			UINT64_C(0x0000000000000080)
+#define	PCS_MISC_CTL_SAMP_PT			UINT64_C(0x000000000000007f)
 
 #endif /* _OCTEON_GMXREG_H_ */

Index: src/sys/arch/mips/cavium/dev/octeon_gmxvar.h
diff -u src/sys/arch/mips/cavium/dev/octeon_gmxvar.h:1.6 src/sys/arch/mips/cavium/dev/octeon_gmxvar.h:1.7
--- src/sys/arch/mips/cavium/dev/octeon_gmxvar.h:1.6	Mon Jun 22 02:26:20 2020
+++ src/sys/arch/mips/cavium/dev/octeon_gmxvar.h	Tue Jun 23 05:17:13 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: octeon_gmxvar.h,v 1.6 2020/06/22 02:26:20 simonb Exp $	*/
+/*	$NetBSD: octeon_gmxvar.h,v 1.7 2020/06/23 05:17:13 simonb Exp $	*/
 
 /*
  * Copyright (c) 2007 Internet Initiative Japan, Inc.
@@ -29,8 +29,6 @@
 #ifndef _OCTEON_GMXVAR_H_
 #define _OCTEON_GMXVAR_H_
 
-#include "opt_octeon.h"
-
 #include <net/if.h>
 #include <net/if_media.h>
 #include <net/if_ether.h>
@@ -40,7 +38,8 @@
 #define GMX_MII_PORT	1
 #define GMX_GMII_PORT	2
 #define GMX_RGMII_PORT	3
-#define GMX_SPI42_PORT	4
+#define GMX_SGMII_PORT	4
+#define GMX_SPI42_PORT	5
 
 #define GMX_FRM_MAX_SIZ	0x600
 
@@ -66,6 +65,7 @@ struct octgmx_port_softc {
 	struct octgmx_port_ops
 				*sc_port_ops;
 	struct octasx_softc	*sc_port_asx;
+	bus_space_handle_t	sc_port_pcs_regh;
 	struct octipd_softc	*sc_ipd;
 	int			sc_port_flowflags;
 
@@ -93,50 +93,31 @@ struct octgmx_attach_args {
 	const char		*ga_name;
 	int			ga_portno;
 	int			ga_port_type;
+	struct octsmi_softc	*ga_smi;
 
 	struct octgmx_softc	*ga_gmx;
 	struct octgmx_port_softc
 				*ga_gmx_port;
 };
 
-#define	OCTEON_GMX_FILTER_NADDRS_MAX	8	/* XXX elsewhere */
-
-enum OCTEON_GMX_FILTER_POLICY {
-	OCTEON_GMX_FILTER_POLICY_ACCEPT_ALL,
-	OCTEON_GMX_FILTER_POLICY_ACCEPT,
-	OCTEON_GMX_FILTER_POLICY_REJECT,
-	OCTEON_GMX_FILTER_POLICY_REJECT_ALL
-};
-
-int		octgmx_link_enable(struct octgmx_port_softc *, int);
-int		octgmx_tx_stats_rd_clr(struct octgmx_port_softc *, int);
-int		octgmx_rx_stats_rd_clr(struct octgmx_port_softc *, int);
-void		octgmx_rx_stats_dec_bad(struct octgmx_port_softc *);
+int		octgmx_port_enable(struct octgmx_port_softc *, int);
 int		octgmx_stats_init(struct octgmx_port_softc *);
-void		octgmx_tx_int_enable(struct octgmx_port_softc *, int);
-void		octgmx_rx_int_enable(struct octgmx_port_softc *, int);
-int		octgmx_setfilt(struct octgmx_port_softc *,
-		    enum OCTEON_GMX_FILTER_POLICY, size_t, uint8_t **);
-int		octgmx_rx_frm_ctl_enable(struct octgmx_port_softc *, uint64_t);
-int		octgmx_rx_frm_ctl_disable(struct octgmx_port_softc *, uint64_t);
-int		octgmx_tx_thresh(struct octgmx_port_softc *, int);
-int		octgmx_set_mac_addr(struct octgmx_port_softc *, uint8_t *);
+void		octgmx_stats(struct octgmx_port_softc *);
+int		octgmx_set_mac_addr(struct octgmx_port_softc *, const uint8_t *);
 int		octgmx_set_filter(struct octgmx_port_softc *);
-int		octgmx_port_enable(struct octgmx_port_softc *, int);
+int		octgmx_tx_stats_rd_clr(struct octgmx_port_softc *, int);
+int		octgmx_rx_stats_rd_clr(struct octgmx_port_softc *, int);
 int		octgmx_reset_speed(struct octgmx_port_softc *);
 int		octgmx_reset_flowctl(struct octgmx_port_softc *);
 int		octgmx_reset_timing(struct octgmx_port_softc *);
-int		octgmx_reset_board(struct octgmx_port_softc *);
-void		octgmx_stats(struct octgmx_port_softc *);
-uint64_t	octgmx_get_rx_int_reg(struct octgmx_port_softc *sc);
-uint64_t	octgmx_get_tx_int_reg(struct octgmx_port_softc *sc);
 static __inline int	octgmx_link_status(struct octgmx_port_softc *);
 
-/* XXX RGMII specific */
 static __inline int
 octgmx_link_status(struct octgmx_port_softc *sc)
 {
-	return (sc->sc_link & RXN_RX_INBND_STATUS) ? 1 : 0;
+
+	return ((sc->sc_port_mii->mii_media_status & (IFM_AVALID | IFM_ACTIVE))
+	    == (IFM_AVALID | IFM_ACTIVE));
 }
 
 #endif /* _OCTEON_GMXVAR_H_ */

Reply via email to