code:
/*	$OpenBSD: cn30xxgmx.c,v 1.20 2015/07/19 23:46:50 jasper Exp $	*/

/*
 * 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.
 */

/*
 *  support GMX0 interface only
 *  take no thought for other GMX interface
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/types.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/syslog.h>

#include <machine/bus.h>
#include <machine/octeon_model.h>
#include <machine/octeonvar.h>

#include <octeon/dev/iobusvar.h>
#include <octeon/dev/cn30xxciureg.h>
#include <octeon/dev/cn30xxgmxreg.h>
#include <octeon/dev/cn30xxipdvar.h>
#include <octeon/dev/cn30xxasxvar.h>
#include <octeon/dev/cn30xxgmxvar.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_RD8(sc, off) \
	bus_space_read_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_gmx->sc_regh, (off))
#define	_GMX_WR8(sc, off, v) \
	bus_space_write_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_gmx->sc_regh, (off), (v))
#define	_GMX_PORT_RD8(sc, off) \
	bus_space_read_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_regh, (off))
#define	_GMX_PORT_WR8(sc, off, v) \
	bus_space_write_8((sc)->sc_port_gmx->sc_regt, (sc)->sc_port_regh, (off), (v))

struct cn30xxgmx_port_ops {
	int	(*port_ops_enable)(struct cn30xxgmx_port_softc *, int);
	int	(*port_ops_speed)(struct cn30xxgmx_port_softc *);
	int	(*port_ops_timing)(struct cn30xxgmx_port_softc *);
	int	(*port_ops_set_mac_addr)(struct cn30xxgmx_port_softc *,
		    uint8_t *, uint64_t);
	int	(*port_ops_set_filter)(struct cn30xxgmx_port_softc *);
};

int	cn30xxgmx_match(struct device *, void *, void *);
void	cn30xxgmx_attach(struct device *, struct device *, void *);
int	cn30xxgmx_print(void *, const char *);
int	cn30xxgmx_submatch(struct device *, void *, void *);
int	cn30xxgmx_port_phy_addr(int);
int	cn30xxgmx_init(struct cn30xxgmx_softc *);
int	cn30xxgmx_rx_frm_ctl_xable(struct cn30xxgmx_port_softc *,
	    uint64_t, int);
int	cn30xxgmx_rgmii_enable(struct cn30xxgmx_port_softc *, int);
int	cn30xxgmx_rgmii_speed(struct cn30xxgmx_port_softc *);
int	cn30xxgmx_rgmii_speed_newlink(struct cn30xxgmx_port_softc *,
	    uint64_t *);
int	cn30xxgmx_rgmii_speed_speed(struct cn30xxgmx_port_softc *);
int	cn30xxgmx_rgmii_timing(struct cn30xxgmx_port_softc *);
int	cn30xxgmx_rgmii_set_mac_addr(struct cn30xxgmx_port_softc *,
	    uint8_t *, uint64_t);
int	cn30xxgmx_rgmii_set_filter(struct cn30xxgmx_port_softc *);
int	cn30xxgmx_tx_ovr_bp_enable(struct cn30xxgmx_port_softc *, int);
int	cn30xxgmx_rx_pause_enable(struct cn30xxgmx_port_softc *, int);

#ifdef OCTEON_ETH_DEBUG
void	cn30xxgmx_dump(void);
void	cn30xxgmx_debug_reset(void);
int	cn30xxgmx_intr_drop(void *);
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_mii = {
	/* XXX not implemented */
};

struct cn30xxgmx_port_ops cn30xxgmx_port_ops_gmii = {
	.port_ops_enable = cn30xxgmx_rgmii_enable,
	.port_ops_speed = cn30xxgmx_rgmii_speed,
	.port_ops_timing = cn30xxgmx_rgmii_timing,
	.port_ops_set_mac_addr = cn30xxgmx_rgmii_set_mac_addr,
	.port_ops_set_filter = cn30xxgmx_rgmii_set_filter
};

struct cn30xxgmx_port_ops cn30xxgmx_port_ops_rgmii = {
	.port_ops_enable = cn30xxgmx_rgmii_enable,
	.port_ops_speed = cn30xxgmx_rgmii_speed,
	.port_ops_timing = cn30xxgmx_rgmii_timing,
	.port_ops_set_mac_addr = cn30xxgmx_rgmii_set_mac_addr,
	.port_ops_set_filter = cn30xxgmx_rgmii_set_filter
};

struct cn30xxgmx_port_ops cn30xxgmx_port_ops_spi42 = {
	/* XXX not implemented */
};

struct cn30xxgmx_port_ops *cn30xxgmx_port_ops[] = {
	[GMX_MII_PORT] = &cn30xxgmx_port_ops_mii,
	[GMX_GMII_PORT] = &cn30xxgmx_port_ops_gmii,
	[GMX_RGMII_PORT] = &cn30xxgmx_port_ops_rgmii,
	[GMX_SPI42_PORT] = &cn30xxgmx_port_ops_spi42
};

#ifdef OCTEON_ETH_DEBUG
void	*cn30xxgmx_intr_drop_ih;

struct cn30xxgmx_port_softc *__cn30xxgmx_port_softc[3/* XXX */];
#endif

struct cfattach cn30xxgmx_ca = {sizeof(struct cn30xxgmx_softc),
    cn30xxgmx_match, cn30xxgmx_attach, NULL, NULL};

struct cfdriver cn30xxgmx_cd = {NULL, "cn30xxgmx", DV_DULL};

int
cn30xxgmx_match(struct device *parent, void *match, void *aux)
{
	struct cfdata *cf = (struct cfdata *)match;
	struct iobus_attach_args *aa = aux;

	if (strcmp(cf->cf_driver->cd_name, aa->aa_name) != 0)
		return 0;
	if (cf->cf_unit != aa->aa_unitno)
		return 0;
	return 1;
}

int
cn30xxgmx_port_phy_addr(int port)
{
	static const int octeon_eth_phy_table[] = {
		/* portwell cam-0100 */
		0x02, 0x03, 0x22
	};

	switch (octeon_boot_info->board_type) {
	case BOARD_TYPE_UBIQUITI_E100:	/* port 0: 7, port 1: 6 */
		if (port > 2)
			return -1;
		return 7 - port;

	default:
		if (port >= nitems(octeon_eth_phy_table))
			return -1;
		return octeon_eth_phy_table[port];
	}
}

void
cn30xxgmx_attach(struct device *parent, struct device *self, void *aux)
{
	struct cn30xxgmx_softc *sc = (void *)self;
	struct iobus_attach_args *aa = aux;
	struct cn30xxgmx_attach_args gmx_aa;
	int status;
	int i;
	struct cn30xxgmx_port_softc *port_sc;

	printf("\n");

	sc->sc_regt = aa->aa_bust; /* XXX why there are iot? */

	status = bus_space_map(sc->sc_regt, aa->aa_addr,
	    GMX0_BASE_IF_SIZE, 0, &sc->sc_regh);
	if (status != 0)
		panic(": can't map register");

	cn30xxgmx_init(sc);

	sc->sc_ports = mallocarray(sc->sc_nports, sizeof(*sc->sc_ports),
	    M_DEVBUF, M_NOWAIT | M_ZERO);

	for (i = 0; i < sc->sc_nports; i++) {
		port_sc = &sc->sc_ports[i];
		port_sc->sc_port_gmx = sc;
		port_sc->sc_port_no = i;
		port_sc->sc_port_type = sc->sc_port_types[i];
		port_sc->sc_port_ops = cn30xxgmx_port_ops[port_sc->sc_port_type];
		status = bus_space_map(sc->sc_regt,
		    aa->aa_addr + GMX0_BASE_PORT_SIZE * i,
		    GMX0_BASE_PORT_SIZE, 0, &port_sc->sc_port_regh);
		if (status != 0)
			panic(": can't map port register");

		(void)memset(&gmx_aa, 0, sizeof(gmx_aa));
		gmx_aa.ga_regt = aa->aa_bust;
		gmx_aa.ga_dmat = aa->aa_dmat;
		gmx_aa.ga_addr = aa->aa_addr;
		gmx_aa.ga_name = "cnmac";
		gmx_aa.ga_portno = i;
		gmx_aa.ga_port_type = sc->sc_port_types[i];
		gmx_aa.ga_gmx = sc;
		gmx_aa.ga_gmx_port = port_sc;
		gmx_aa.ga_phy_addr = cn30xxgmx_port_phy_addr(i);
		if (gmx_aa.ga_phy_addr == -1)
			panic(": don't know phy address for port %d", i);

		config_found_sm(self, &gmx_aa,
		    cn30xxgmx_print, cn30xxgmx_submatch);

#ifdef OCTEON_ETH_DEBUG
		__cn30xxgmx_port_softc[i] = port_sc;
#endif
	}

#ifdef OCTEON_ETH_DEBUG
	if (cn30xxgmx_intr_drop_ih == NULL)
		cn30xxgmx_intr_drop_ih = octeon_intr_establish(
		   ffs64(CIU_INTX_SUM0_GMX_DRP) - 1, IPL_NET,
		   cn30xxgmx_intr_drop, NULL, "cn30xxgmx");
#endif
}

int
cn30xxgmx_print(void *aux, const char *pnp)
{
	struct cn30xxgmx_attach_args *ga = aux;
	static const char *types[] = {
		[GMX_MII_PORT] = "MII",
		[GMX_GMII_PORT] = "GMII",
		[GMX_RGMII_PORT] = "RGMII"
	};

#if DEBUG
	if (pnp)
		printf("%s at %s", ga->ga_name, pnp);
#endif

	printf(": %s", types[ga->ga_port_type]);

	return UNCONF;
}

int
cn30xxgmx_submatch(struct device *parent, void *vcf, void *aux)
{
	struct cfdata *cf = vcf;

	return (*cf->cf_attach->ca_match)(parent, vcf, aux);
}

int
cn30xxgmx_init(struct cn30xxgmx_softc *sc)
{
	int result = 0;
	uint64_t inf_mode;
	int id;

	inf_mode = bus_space_read_8(sc->sc_regt, sc->sc_regh, GMX0_INF_MODE);
	if ((inf_mode & INF_MODE_EN) == 0) {
		printf("port are disable\n");
		sc->sc_nports = 0;
		result = 1;
		return result;
	}

	id = octeon_get_chipid();

	switch (octeon_model_family(id)) {
	case OCTEON_MODEL_FAMILY_CN31XX:
		/*
		 * CN31XX-HM-1.01
		 * 14.1 Packet Interface Introduction
		 * Table 14-1 Packet Interface Configuration
		 * 14.8 GMX Registers, Interface Mode Register, GMX0_INF_MODE
		 */
		if ((inf_mode & INF_MODE_TYPE) == 0) {
			/* all three ports configured as RGMII */
			sc->sc_nports = 3;
			sc->sc_port_types[0] = GMX_RGMII_PORT;
			sc->sc_port_types[1] = GMX_RGMII_PORT;
			sc->sc_port_types[2] = GMX_RGMII_PORT;
		} else {
			/* port 0: RGMII, port 1: GMII, port 2: disabled */
			/* XXX CN31XX-HM-1.01 says "Port 3: disabled"; typo? */
			sc->sc_nports = 2;
			sc->sc_port_types[0] = GMX_RGMII_PORT;
			sc->sc_port_types[1] = GMX_GMII_PORT;
		}
		break;
	case OCTEON_MODEL_FAMILY_CN30XX:
	case OCTEON_MODEL_FAMILY_CN50XX:
		/*
		 * CN30XX-HM-1.0
		 * 13.1 Packet Interface Introduction
		 * Table 13-1 Packet Interface Configuration
		 * 13.8 GMX Registers, Interface Mode Register, GMX0_INF_MODE
		 */
		if ((inf_mode & INF_MODE_P0MII) == 0)
			sc->sc_port_types[0] = GMX_RGMII_PORT;
		else
			sc->sc_port_types[0] = GMX_MII_PORT;
		if ((inf_mode & INF_MODE_TYPE) == 0) {
			/* port 1 and 2 are configred as RGMII ports */
			sc->sc_nports = 3;
			sc->sc_port_types[1] = GMX_RGMII_PORT;
			sc->sc_port_types[2] = GMX_RGMII_PORT;
		} else {
			/* port 1: GMII/MII, port 2: disabled */
			/* GMII or MII port is slected by GMX_PRT1_CFG[SPEED] */
			sc->sc_nports = 2;
			sc->sc_port_types[1] = GMX_GMII_PORT;
		}
		/* port 2 is in CN3010/CN5010 only */
		if ((octeon_model(id) != OCTEON_MODEL_CN3010) &&
		    (octeon_model(id) != OCTEON_MODEL_CN5010))
			if (sc->sc_nports == 3)
				sc->sc_nports = 2;
		break;
	case OCTEON_MODEL_FAMILY_CN38XX:
	case OCTEON_MODEL_FAMILY_CN56XX:
	case OCTEON_MODEL_FAMILY_CN58XX:
	default:
		printf("unsupported octeon model: 0x%x\n", octeon_get_chipid());
		sc->sc_nports = 0;
		result = 1;
		break;
	}

	return result;
}

/* XXX RGMII specific */
int
cn30xxgmx_link_enable(struct cn30xxgmx_port_softc *sc, int enable)
{
	uint64_t prt_cfg;

	cn30xxgmx_tx_int_enable(sc, enable);
	cn30xxgmx_rx_int_enable(sc, enable);

	prt_cfg = _GMX_PORT_RD8(sc, GMX0_PRT0_CFG);
	if (enable) {
		if (cn30xxgmx_link_status(sc)) {
			SET(prt_cfg, PRTN_CFG_EN);
		}
	} else {
		CLR(prt_cfg, PRTN_CFG_EN);
	}
	_GMX_PORT_WR8(sc, GMX0_PRT0_CFG, prt_cfg);
	/*
	 * According to CN30XX-HM-1.0, 13.4.2 Link Status Changes:
	 * > software should read back to flush the write operation.
	 */
	(void)_GMX_PORT_RD8(sc, GMX0_PRT0_CFG);

	return 0;
}

/* XXX RGMII specific */
int
cn30xxgmx_stats_init(struct cn30xxgmx_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);
	return 0;
}

int
cn30xxgmx_tx_stats_rd_clr(struct cn30xxgmx_port_softc *sc, int enable)
{
	_GMX_PORT_WR8(sc, GMX0_TX0_STATS_CTL, enable ? 0x1ULL : 0x0ULL);
	return 0;
}

int
cn30xxgmx_rx_stats_rd_clr(struct cn30xxgmx_port_softc *sc, int enable)
{
	_GMX_PORT_WR8(sc, GMX0_RX0_STATS_CTL, enable ? 0x1ULL : 0x0ULL);
	return 0;
}

void
cn30xxgmx_rx_stats_dec_bad(struct cn30xxgmx_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);
}

int
cn30xxgmx_tx_ovr_bp_enable(struct cn30xxgmx_port_softc *sc, int enable)
{
	uint64_t ovr_bp;

	ovr_bp = _GMX_RD8(sc, GMX0_TX_OVR_BP);
	if (enable) {
		CLR(ovr_bp, (1 << sc->sc_port_no) << TX_OVR_BP_EN_SHIFT);
		SET(ovr_bp, (1 << sc->sc_port_no) << TX_OVR_BP_BP_SHIFT);
		/* XXX really??? */
		SET(ovr_bp, (1 << sc->sc_port_no) << TX_OVR_BP_IGN_FULL_SHIFT);
	} else {
		SET(ovr_bp, (1 << sc->sc_port_no) << TX_OVR_BP_EN_SHIFT);
		CLR(ovr_bp, (1 << sc->sc_port_no) << TX_OVR_BP_BP_SHIFT);
		/* XXX really??? */
		SET(ovr_bp, (1 << sc->sc_port_no) << TX_OVR_BP_IGN_FULL_SHIFT);
	}
	_GMX_WR8(sc, GMX0_TX_OVR_BP, ovr_bp);
	return 0;
}

int
cn30xxgmx_rx_pause_enable(struct cn30xxgmx_port_softc *sc, int enable)
{
	if (enable) {
		cn30xxgmx_rx_frm_ctl_enable(sc, RXN_FRM_CTL_CTL_BCK);
	} else {
		cn30xxgmx_rx_frm_ctl_disable(sc, RXN_FRM_CTL_CTL_BCK);
	}

	return 0;
}

void
cn30xxgmx_tx_int_enable(struct cn30xxgmx_port_softc *sc, int enable)
{
	uint64_t tx_int_xxx = 0;

	SET(tx_int_xxx,
	    TX_INT_REG_LATE_COL |
	    TX_INT_REG_XSDEF |
	    TX_INT_REG_XSCOL |
	    TX_INT_REG_UNDFLW |
	    TX_INT_REG_PKO_NXA);
	_GMX_WR8(sc, GMX0_TX_INT_REG, tx_int_xxx);
	_GMX_WR8(sc, GMX0_TX_INT_EN, enable ? tx_int_xxx : 0);
}

void
cn30xxgmx_rx_int_enable(struct cn30xxgmx_port_softc *sc, int enable)
{
	uint64_t rx_int_xxx = 0;

	SET(rx_int_xxx, 0 |
	    RXN_INT_REG_PHY_DUPX |
	    RXN_INT_REG_PHY_SPD |
	    RXN_INT_REG_PHY_LINK |
	    RXN_INT_REG_IFGERR |
	    RXN_INT_REG_COLDET |
	    RXN_INT_REG_FALERR |
	    RXN_INT_REG_RSVERR |
	    RXN_INT_REG_PCTERR |
	    RXN_INT_REG_OVRERR |
	    RXN_INT_REG_NIBERR |
	    RXN_INT_REG_SKPERR |
	    RXN_INT_REG_RCVERR |
	    RXN_INT_REG_LENERR |
	    RXN_INT_REG_ALNERR |
	    RXN_INT_REG_FCSERR |
	    RXN_INT_REG_JABBER |
	    RXN_INT_REG_MAXERR |
	    RXN_INT_REG_CAREXT |
	    RXN_INT_REG_MINERR);
	_GMX_PORT_WR8(sc, GMX0_RX0_INT_REG, rx_int_xxx);
	_GMX_PORT_WR8(sc, GMX0_RX0_INT_EN, enable ? rx_int_xxx : 0);
}

int
cn30xxgmx_rx_frm_ctl_enable(struct cn30xxgmx_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);

	return cn30xxgmx_rx_frm_ctl_xable(sc, rx_frm_ctl, 1);
}

int
cn30xxgmx_rx_frm_ctl_disable(struct cn30xxgmx_port_softc *sc,
    uint64_t rx_frm_ctl)
{
	return cn30xxgmx_rx_frm_ctl_xable(sc, rx_frm_ctl, 0);
}

int
cn30xxgmx_rx_frm_ctl_xable(struct cn30xxgmx_port_softc *sc,
    uint64_t rx_frm_ctl, int enable)
{
	uint64_t tmp;

	tmp = _GMX_PORT_RD8(sc, GMX0_RX0_FRM_CTL);
	if (enable)
		SET(tmp, rx_frm_ctl);
	else
		CLR(tmp, rx_frm_ctl);
	_GMX_PORT_WR8(sc, GMX0_RX0_FRM_CTL, tmp);

	return 0;
}

int
cn30xxgmx_tx_thresh(struct cn30xxgmx_port_softc *sc, int cnt)
{
	_GMX_PORT_WR8(sc, GMX0_TX0_THRESH, cnt);
	return 0;
}

int
cn30xxgmx_set_mac_addr(struct cn30xxgmx_port_softc *sc, uint8_t *addr)
{
	uint64_t mac = 0;

	ADDR2UINT64(mac, addr);
	(*sc->sc_port_ops->port_ops_set_mac_addr)(sc, addr, mac);
	return 0;
}

int
cn30xxgmx_set_filter(struct cn30xxgmx_port_softc *sc)
{
	(*sc->sc_port_ops->port_ops_set_filter)(sc);
	return 0;
}

int
cn30xxgmx_port_enable(struct cn30xxgmx_port_softc *sc, int enable)
{
	(*sc->sc_port_ops->port_ops_enable)(sc, enable);
	return 0;
}

int
cn30xxgmx_reset_speed(struct cn30xxgmx_port_softc *sc)
{
	struct ifnet *ifp = &sc->sc_port_ac->ac_if;
	if (ISSET(sc->sc_port_mii->mii_flags, MIIF_DOINGAUTO)) {
		log(LOG_WARNING,
		    "%s: autonegotiation has not been completed yet\n",
		    ifp->if_xname);
		return 1;
	}
	(*sc->sc_port_ops->port_ops_speed)(sc);
	return 0;
}

int
cn30xxgmx_reset_timing(struct cn30xxgmx_port_softc *sc)
{
	(*sc->sc_port_ops->port_ops_timing)(sc);
	return 0;
}

int
cn30xxgmx_reset_board(struct cn30xxgmx_port_softc *sc)
{

	return 0;
}

int
cn30xxgmx_reset_flowctl(struct cn30xxgmx_port_softc *sc)
{
	struct ifmedia_entry *ife = sc->sc_port_mii->mii_media.ifm_cur;

	/*
	 * Get flow control negotiation result.
	 */
#ifdef GMX_802_3X_DISABLE_AUTONEG
	/* Tentative support for SEIL-compat.. */
	if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
		sc->sc_port_flowflags &= ~IFM_ETH_FMASK;
	}
#else
	/* Default configuration of NetBSD */
	if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO &&
	    (sc->sc_port_mii->mii_media_active & IFM_ETH_FMASK) !=
			sc->sc_port_flowflags) {
		sc->sc_port_flowflags =
			sc->sc_port_mii->mii_media_active & IFM_ETH_FMASK;
		sc->sc_port_mii->mii_media_active &= ~IFM_ETH_FMASK;
	}
#endif /* GMX_802_3X_DISABLE_AUTONEG */

	/*
	 * 802.3x Flow Control Capabilities
	 */
	if (sc->sc_port_flowflags & IFM_ETH_TXPAUSE) {
		cn30xxgmx_tx_ovr_bp_enable(sc, 1);
	} else {
		cn30xxgmx_tx_ovr_bp_enable(sc, 0);
	}
	if (sc->sc_port_flowflags & IFM_ETH_RXPAUSE) {
		cn30xxgmx_rx_pause_enable(sc, 1);
	} else {
		cn30xxgmx_rx_pause_enable(sc, 0);
	}

	return 0;
}

int
cn30xxgmx_rgmii_enable(struct cn30xxgmx_port_softc *sc, int enable)
{
	uint64_t mode;

	/* XXX */
	mode = _GMX_RD8(sc, GMX0_INF_MODE);
	if (ISSET(mode, INF_MODE_EN)) {
		cn30xxasx_enable(sc->sc_port_asx, 1);
	}

	return 0;
}

int
cn30xxgmx_rgmii_speed(struct cn30xxgmx_port_softc *sc)
{
	struct ifnet *ifp = &sc->sc_port_ac->ac_if;
	uint64_t newlink;
	int baudrate;

	/* XXX */
	cn30xxgmx_link_enable(sc, 1);

	cn30xxgmx_rgmii_speed_newlink(sc, &newlink);
	if (sc->sc_link == newlink) {
		return 0;
	}
#ifdef OCTEON_ETH_DEBUG
	cn30xxgmx_rgmii_speed_newlink_log(sc, newlink);
#endif
	sc->sc_link = newlink;

	switch (sc->sc_link & RXN_RX_INBND_SPEED) {
	case RXN_RX_INBND_SPEED_2_5:
		baudrate = IF_Mbps(10);
		break;
	case RXN_RX_INBND_SPEED_25:
		baudrate = IF_Mbps(100);
		break;
	case RXN_RX_INBND_SPEED_125:
		baudrate = IF_Gbps(1);
		break;
	default:
		baudrate = 0/* XXX */;
		break;
	}
	ifp->if_baudrate = baudrate;

	cn30xxgmx_link_enable(sc, 0);

	/*
	 * According to CN30XX-HM-1.0, 13.4.2 Link Status Changes:
	 * wait a max_packet_time
	 * max_packet_time(us) = (max_packet_size(bytes) * 8) / link_speed(Mbps)
	 */
	delay((GMX_FRM_MAX_SIZ * 8) / (baudrate / 1000000));

	cn30xxgmx_rgmii_speed_speed(sc);

	cn30xxgmx_link_enable(sc, 1);
	cn30xxasx_enable(sc->sc_port_asx, 1);

	return 0;
}

int
cn30xxgmx_rgmii_speed_newlink(struct cn30xxgmx_port_softc *sc,
    uint64_t *rnewlink)
{
	uint64_t newlink;

	/* Inband status does not seem to work */
	newlink = _GMX_PORT_RD8(sc, GMX0_RX0_RX_INBND);

	*rnewlink = newlink;
	return 0;
}

#ifdef OCTEON_ETH_DEBUG
int
cn30xxgmx_rgmii_speed_newlink_log(struct cn30xxgmx_port_softc *sc,
    uint64_t newlink)
{
	struct ifnet *ifp = &sc->sc_port_ac->ac_if;
	const char *status_str;
	const char *speed_str;
	const char *duplex_str;
	int is_status_changed;
	int is_speed_changed;
	int is_linked;
	char status_buf[80/* XXX */];
	char speed_buf[80/* XXX */];

	is_status_changed = (newlink & RXN_RX_INBND_STATUS) !=
	    (sc->sc_link & RXN_RX_INBND_STATUS);
	is_speed_changed = (newlink & RXN_RX_INBND_SPEED) !=
	    (sc->sc_link & RXN_RX_INBND_SPEED);
	is_linked = ISSET(newlink, RXN_RX_INBND_STATUS);
	if (is_status_changed) {
		if (is_linked)
			status_str = "link up";
		else
			status_str = "link down";
	} else {
		if (is_linked) {
			/* any other conditions? */
			if (is_speed_changed)
				status_str = "link change";
			else
				status_str = NULL;
		} else {
			status_str = NULL;
		}
	}

	if (status_str != NULL) {
		if ((is_speed_changed && is_linked) || is_linked) {
			switch (newlink & RXN_RX_INBND_SPEED) {
			case RXN_RX_INBND_SPEED_2_5:
				speed_str = "10baseT";
				break;
			case RXN_RX_INBND_SPEED_25:
				speed_str = "100baseTX";
				break;
			case RXN_RX_INBND_SPEED_125:
				speed_str = "1000baseT";
				break;
			default:
				panic("Unknown link speed");
				break;
			}

			if (ISSET(newlink, RXN_RX_INBND_DUPLEX))
				duplex_str = "-FDX";
			else
				duplex_str = "";

			(void)snprintf(speed_buf, sizeof(speed_buf), "(%s%s)",
			    speed_str, duplex_str);
		} else {
			speed_buf[0] = '\0';
		}
		(void)snprintf(status_buf, sizeof(status_buf), "%s: %s%s%s\n",
		    ifp->if_xname, status_str, (is_speed_changed | is_linked) ? " " : "",
		    speed_buf);
		log(LOG_CRIT, status_buf);
	}

	return 0;
}
#endif

int
cn30xxgmx_rgmii_speed_speed(struct cn30xxgmx_port_softc *sc)
{
	uint64_t prt_cfg;
	uint64_t tx_clk, tx_slot, tx_burst;

	prt_cfg = _GMX_PORT_RD8(sc, GMX0_PRT0_CFG);

	switch (sc->sc_link & RXN_RX_INBND_SPEED) {
	case RXN_RX_INBND_SPEED_2_5:
		/* 10Mbps */
		/*
		 * "GMX Tx Clock Generation Registers", CN30XX-HM-1.0;
		 * > 8ns x 50 = 400ns (2.5MHz TXC clock)
		 */
		tx_clk = 50;
		/*
		 * "TX Slottime Counter Registers", CN30XX-HM-1.0;
		 * > 10/100Mbps: set SLOT to 0x40
		 */
		tx_slot = 0x40;
		/*
		 * "TX Burst-Counter Registers", CN30XX-HM-1.0;
		 * > 10/100Mbps: set BURST to 0x0
		 */
		tx_burst = 0;
		/*
		 * "GMX Tx Port Configuration Registers", CN30XX-HM-1.0;
		 * > Slot time for half-duplex operation
		 * >   0 = 512 bittimes (10/100Mbps operation)
		 */
		CLR(prt_cfg, PRTN_CFG_SLOTTIME);
		/*
		 * "GMX Port Configuration Registers", CN30XX-HM-1.0;
		 * > Link speed
		 * >   0 = 10/100Mbps operation
		 * >     in RGMII mode: GMX0_TX(0..2)_CLK[CLK_CNT] > 1
		 */
		CLR(prt_cfg, PRTN_CFG_SPEED);
		break;
	case RXN_RX_INBND_SPEED_25:
		/* 100Mbps */
		/*
		 * "GMX Tx Clock Generation Registers", CN30XX-HM-1.0;
		 * > 8ns x 5 = 40ns (25.0MHz TXC clock)
		 */
		tx_clk = 5;
		/*
		 * "TX Slottime Counter Registers", CN30XX-HM-1.0;
		 * > 10/100Mbps: set SLOT to 0x40
		 */
		tx_slot = 0x40;
		/*
		 * "TX Burst-Counter Registers", CN30XX-HM-1.0;
		 * > 10/100Mbps: set BURST to 0x0
		 */
		tx_burst = 0;
		/*
		 * "GMX Tx Port Configuration Registers", CN30XX-HM-1.0;
		 * > Slot time for half-duplex operation
		 * >   0 = 512 bittimes (10/100Mbps operation)
		 */
		CLR(prt_cfg, PRTN_CFG_SLOTTIME);
		/*
		 * "GMX Port Configuration Registers", CN30XX-HM-1.0;
		 * > Link speed
		 * >   0 = 10/100Mbps operation
		 * >     in RGMII mode: GMX0_TX(0..2)_CLK[CLK_CNT] > 1
		 */
		CLR(prt_cfg, PRTN_CFG_SPEED);
		break;
	case RXN_RX_INBND_SPEED_125:
		/* 1000Mbps */
		/*
		 * "GMX Tx Clock Generation Registers", CN30XX-HM-1.0;
		 * > 8ns x 1 = 8ns (125.0MHz TXC clock)
		 */
		tx_clk = 1;
		/*
		 * "TX Slottime Counter Registers", CN30XX-HM-1.0;
		 * > 1000Mbps: set SLOT to 0x200
		 */
		tx_slot = 0x200;
		/*
		 * "TX Burst-Counter Registers", CN30XX-HM-1.0;
		 * > 1000Mbps: set BURST to 0x2000
		 */
		tx_burst = 0x2000;
		/*
		 * "GMX Tx Port Configuration Registers", CN30XX-HM-1.0;
		 * > Slot time for half-duplex operation
		 * >   1 = 4096 bittimes (1000Mbps operation)
		 */
		SET(prt_cfg, PRTN_CFG_SLOTTIME);
		/*
		 * "GMX Port Configuration Registers", CN30XX-HM-1.0;
		 * > Link speed
		 * >   1 = 1000Mbps operation
		 */
		SET(prt_cfg, PRTN_CFG_SPEED);
		break;
	default:
		/* NOT REACHED! */
		/* Following configuration is default value of system.
		*/
		tx_clk = 1;
		tx_slot = 0x200;
		tx_burst = 0x2000;
		SET(prt_cfg, PRTN_CFG_SLOTTIME);
		SET(prt_cfg, PRTN_CFG_SPEED);
		break;
	}

	/* Setup Duplex mode(negotiated) */
	/*
	 * "GMX Port Configuration Registers", CN30XX-HM-1.0;
	 * > Duplex mode: 0 = half-duplex mode, 1=full-duplex
	 */
	if (ISSET(sc->sc_link, RXN_RX_INBND_DUPLEX)) {
		/* Full-Duplex */
		SET(prt_cfg, PRTN_CFG_DUPLEX);
	} else {
		/* Half-Duplex */
		CLR(prt_cfg, PRTN_CFG_DUPLEX);
	}

	_GMX_PORT_WR8(sc, GMX0_TX0_CLK, tx_clk);
	_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);

	return 0;
}

int
cn30xxgmx_rgmii_timing(struct cn30xxgmx_port_softc *sc)
{
	int clk_tx_setting;
	int clk_rx_setting;
	uint64_t rx_frm_ctl;

	/* RGMII TX Threshold Registers, CN30XX-HM-1.0;
	 * > Number of 16-byte ticks to accumulate in the TX FIFO before
	 * > sending on the RGMII interface. This field should be large
	 * > enough to prevent underflow on the RGMII interface and must
	 * > never be set to less than 0x4. This register cannot exceed
	 * > the TX FIFO depth of 0x40 words.
	 */
	/* Default parameter of CN30XX */
	cn30xxgmx_tx_thresh(sc, 32);

	rx_frm_ctl = 0 |
	    /* RXN_FRM_CTL_NULL_DIS |	(cn5xxx only) */
	    /* RXN_FRM_CTL_PRE_ALIGN |	(cn5xxx only) */
	    /* RXN_FRM_CTL_PAD_LEN |	(cn3xxx only) */
	    /* RXN_FRM_CTL_VLAN_LEN |	(cn3xxx only) */
	    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;
	cn30xxgmx_rx_frm_ctl_enable(sc, rx_frm_ctl);

	/* XXX PHY-dependent parameter */
	/* RGMII RX Clock-Delay Registers, CN30XX-HM-1.0;
	 * > Delay setting to place n RXC (RGMII receive clock) delay line.
	 * > The intrinsic delay can range from 50ps to 80ps per tap,
	 * > which corresponds to skews of 1.25ns to 2.00ns at 25 taps(CSR+1).
	 * > This is the best match for the RGMII specification which wants
	 * > 1ns - 2.6ns of skew.
	 */
	/* RGMII TX Clock-Delay Registers, CN30XX-HM-1.0;
	 * > Delay setting to place n TXC (RGMII transmit clock) delay line.
	 * > ...
	 */

	switch (octeon_boot_info->board_type) {
	default:
		/* Default parameter of CN30XX */
		clk_tx_setting = 24;
		clk_rx_setting = 24;
		break;
	case BOARD_TYPE_UBIQUITI_E100:
		clk_tx_setting = 16;
		clk_rx_setting = 0;
		break;
	}

	cn30xxasx_clk_set(sc->sc_port_asx, clk_tx_setting, clk_rx_setting);

	return 0;
}

int
cn30xxgmx_rgmii_set_mac_addr(struct cn30xxgmx_port_softc *sc, uint8_t *addr,
    uint64_t mac)
{
	int i;

	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;
}

#define	OCTEON_ETH_USE_GMX_CAM

int
cn30xxgmx_rgmii_set_filter(struct cn30xxgmx_port_softc *sc)
{
	struct ifnet *ifp = &sc->sc_port_ac->ac_if;
	struct arpcom *ac = sc->sc_port_ac;
#ifdef OCTEON_ETH_USE_GMX_CAM
	struct ether_multi *enm;
	struct ether_multistep step;
#endif
	uint64_t cam_en = 0x01ULL;
	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);

	/*
	 * Always accept broadcast frames.
	 */
	SET(ctl, RXN_ADR_CTL_BCST);

	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) {
		SET(ifp->if_flags, IFF_ALLMULTI);
		SET(ctl, RXN_ADR_CTL_MCST_ACCEPT);
	} else {
#ifdef OCTEON_ETH_USE_GMX_CAM
		/*
		 * 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);
			}

			for (i = 0; i < 6; i++)
				dprintf("cam%d = %016llx\n", i,
				    _GMX_PORT_RD8(sc, cn30xxgmx_rx_adr_cam_regs[i]));

			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);
#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);
		SET(ctl, RXN_ADR_CTL_MCST_ACCEPT);
#endif
	}

	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);

	cn30xxgmx_link_enable(sc, 1);

	return 0;
}

void
cn30xxgmx_stats(struct cn30xxgmx_port_softc *sc)
{
	struct ifnet *ifp = &sc->sc_port_ac->ac_if;
	uint64_t tmp;

	ifp->if_ierrors +=
	    (uint32_t)_GMX_PORT_RD8(sc, GMX0_RX0_STATS_PKTS_BAD);
	ifp->if_iqdrops +=
	    (uint32_t)_GMX_PORT_RD8(sc, GMX0_RX0_STATS_PKTS_DRP);
	ifp->if_opackets +=
	    (uint32_t)_GMX_PORT_RD8(sc, GMX0_TX0_STAT3);
	tmp = _GMX_PORT_RD8(sc, GMX0_TX0_STAT0);
	ifp->if_oerrors +=
	    (uint32_t)tmp + ((uint32_t)(tmp >> 32) * 16);
	ifp->if_collisions += ((uint32_t)tmp) * 16;
	tmp = _GMX_PORT_RD8(sc, GMX0_TX0_STAT1);
	ifp->if_collisions +=
	    ((uint32_t)tmp * 2) + (uint32_t)(tmp >> 32);
	tmp = _GMX_PORT_RD8(sc, GMX0_TX0_STAT9);
	ifp->if_oerrors += (uint32_t)(tmp >> 32);
}

/* ---- 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			CN30XXGMX_FILTER_POLICY
#define	_POLICY_ACCEPT_ALL	CN30XXGMX_FILTER_POLICY_ACCEPT_ALL
#define	_POLICY_ACCEPT		CN30XXGMX_FILTER_POLICY_ACCEPT
#define	_POLICY_REJECT		CN30XXGMX_FILTER_POLICY_REJECT
#define	_POLICY_REJECT_ALL	CN30XXGMX_FILTER_POLICY_REJECT_ALL

int	cn30xxgmx_setfilt_addrs(struct cn30xxgmx_port_softc *,
	    size_t, uint8_t **);

int
cn30xxgmx_setfilt(struct cn30xxgmx_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, (policy == _POLICY_ACCEPT_ALL) ?
		    RXN_ADR_CTL_MCST_ACCEPT : RXN_ADR_CTL_MCST_REJECT);
		break;
	case _POLICY_ACCEPT:
	case _POLICY_REJECT:
		if (naddrs > CN30XXGMX_FILTER_NADDRS_MAX)
			return E2BIG;
		SET(rx_adr_ctl, (policy == _POLICY_ACCEPT) ?
		    RXN_ADR_CTL_CAM_MODE : 0);
		SET(rx_adr_ctl, RXN_ADR_CTL_MCST_AFCAM);
		/* set GMX0_RXN_ADR_CAM_EN, GMX0_RXN_ADR_CAM[0-5] */
		cn30xxgmx_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;
}

int
cn30xxgmx_setfilt_addrs(struct cn30xxgmx_port_softc *sc, size_t naddrs,
    uint8_t **addrs)
{
	uint64_t rx_adr_cam_en;
	uint64_t rx_adr_cam_addrs[CN30XXGMX_FILTER_NADDRS_MAX];
	int i, j;

	KASSERT(naddrs <= CN30XXGMX_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, 1ULL << 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, cn30xxgmx_rx_adr_cam_regs[j],
		    rx_adr_cam_addrs[j]);

	return 0;
}
#endif

/* ---- interrupt */

#ifdef OCTEON_ETH_DEBUG
void	cn30xxgmx_intr_rml_gmx0(void);

int	cn30xxgmx_intr_rml_verbose;

void
cn30xxgmx_intr_rml_gmx0(void)
{
	struct cn30xxgmx_port_softc *sc;
	int i;
	uint64_t reg;

	sc = __cn30xxgmx_port_softc[0];
	if (sc == NULL)
		return;

	/* GMX0_RXn_INT_REG or GMX0_TXn_INT_REG */
	reg = cn30xxgmx_get_tx_int_reg(sc);
	if (cn30xxgmx_intr_rml_verbose && reg != 0)
		printf("%s: GMX_TX_INT_REG=0x%016llx\n", __func__, reg);

	for (i = 0; i < GMX_PORT_NUNITS; i++) {
		sc = __cn30xxgmx_port_softc[i];
		if (sc == NULL)
			continue;
		reg = cn30xxgmx_get_rx_int_reg(sc);
		if (cn30xxgmx_intr_rml_verbose)
			printf("%s: GMX_RX_INT_REG=0x%016llx\n", __func__, reg);
	}
}

int
cn30xxgmx_intr_drop(void *arg)
{
	octeon_xkphys_write_8(CIU_INT0_SUM0, CIU_INTX_SUM0_GMX_DRP);
	return (1);
}

uint64_t
cn30xxgmx_get_rx_int_reg(struct cn30xxgmx_port_softc *sc)
{
	uint64_t reg;
	uint64_t rx_int_reg = 0;

	reg = _GMX_PORT_RD8(sc, GMX0_RX0_INT_REG);
	/* clear */
	SET(rx_int_reg, 0 |
	    RXN_INT_REG_PHY_DUPX |
	    RXN_INT_REG_PHY_SPD |
	    RXN_INT_REG_PHY_LINK |
	    RXN_INT_REG_IFGERR |
	    RXN_INT_REG_COLDET |
	    RXN_INT_REG_FALERR |
	    RXN_INT_REG_RSVERR |
	    RXN_INT_REG_PCTERR |
	    RXN_INT_REG_OVRERR |
	    RXN_INT_REG_NIBERR |
	    RXN_INT_REG_SKPERR |
	    RXN_INT_REG_RCVERR |
	    RXN_INT_REG_LENERR |
	    RXN_INT_REG_ALNERR |
	    RXN_INT_REG_FCSERR |
	    RXN_INT_REG_JABBER |
	    RXN_INT_REG_MAXERR |
	    RXN_INT_REG_CAREXT |
	    RXN_INT_REG_MINERR);
	_GMX_PORT_WR8(sc, GMX0_RX0_INT_REG, rx_int_reg);

	return reg;
}

uint64_t
cn30xxgmx_get_tx_int_reg(struct cn30xxgmx_port_softc *sc)
{
	uint64_t reg;
	uint64_t tx_int_reg = 0;

	reg = _GMX_PORT_RD8(sc, GMX0_TX_INT_REG);
	/* clear */
	SET(tx_int_reg, 0 |
	    TX_INT_REG_LATE_COL |
	    TX_INT_REG_XSDEF |
	    TX_INT_REG_XSCOL |
	    TX_INT_REG_UNDFLW |
	    TX_INT_REG_PKO_NXA);
	_GMX_PORT_WR8(sc, GMX0_TX_INT_REG, tx_int_reg);

	return reg;
}
#endif	/* OCTEON_ETH_DEBUG */

/* ---- debug */

#ifdef OCTEON_ETH_DEBUG
#define	_ENTRY(x)	{ #x, x }

struct cn30xxgmx_dump_reg_ {
	const char *name;
	size_t	offset;
};

const struct cn30xxgmx_dump_reg_ cn30xxgmx_dump_regs_[] = {
	_ENTRY(GMX0_SMAC0),
	_ENTRY(GMX0_BIST0),
	_ENTRY(GMX0_RX_PRTS),
	_ENTRY(GMX0_RX_BP_DROP0),
	_ENTRY(GMX0_RX_BP_DROP1),
	_ENTRY(GMX0_RX_BP_DROP2),
	_ENTRY(GMX0_RX_BP_ON0),
	_ENTRY(GMX0_RX_BP_ON1),
	_ENTRY(GMX0_RX_BP_ON2),
	_ENTRY(GMX0_RX_BP_OFF0),
	_ENTRY(GMX0_RX_BP_OFF1),
	_ENTRY(GMX0_RX_BP_OFF2),
	_ENTRY(GMX0_TX_PRTS),
	_ENTRY(GMX0_TX_IFG),
	_ENTRY(GMX0_TX_JAM),
	_ENTRY(GMX0_TX_COL_ATTEMPT),
	_ENTRY(GMX0_TX_PAUSE_PKT_DMAC),
	_ENTRY(GMX0_TX_PAUSE_PKT_TYPE),
	_ENTRY(GMX0_TX_OVR_BP),
	_ENTRY(GMX0_TX_BP),
	_ENTRY(GMX0_TX_CORRUPT),
	_ENTRY(GMX0_RX_PRT_INFO),
	_ENTRY(GMX0_TX_LFSR),
	_ENTRY(GMX0_TX_INT_REG),
	_ENTRY(GMX0_TX_INT_EN),
	_ENTRY(GMX0_NXA_ADR),
	_ENTRY(GMX0_BAD_REG),
	_ENTRY(GMX0_STAT_BP),
	_ENTRY(GMX0_TX_CLK_MSK0),
	_ENTRY(GMX0_TX_CLK_MSK1),
	_ENTRY(GMX0_RX_TX_STATUS),
	_ENTRY(GMX0_INF_MODE),
};

const struct cn30xxgmx_dump_reg_ cn30xxgmx_dump_port_regs_[] = {
	_ENTRY(GMX0_RX0_INT_REG),
	_ENTRY(GMX0_RX0_INT_EN),
	_ENTRY(GMX0_PRT0_CFG),
	_ENTRY(GMX0_RX0_FRM_CTL),
	_ENTRY(GMX0_RX0_FRM_CHK),
	_ENTRY(GMX0_RX0_FRM_MIN),
	_ENTRY(GMX0_RX0_FRM_MAX),
	_ENTRY(GMX0_RX0_JABBER),
	_ENTRY(GMX0_RX0_DECISION),
	_ENTRY(GMX0_RX0_UDD_SKP),
	_ENTRY(GMX0_RX0_STATS_CTL),
	_ENTRY(GMX0_RX0_IFG),
	_ENTRY(GMX0_RX0_RX_INBND),
	_ENTRY(GMX0_RX0_ADR_CTL),
	_ENTRY(GMX0_RX0_ADR_CAM_EN),
	_ENTRY(GMX0_RX0_ADR_CAM0),
	_ENTRY(GMX0_RX0_ADR_CAM1),
	_ENTRY(GMX0_RX0_ADR_CAM2),
	_ENTRY(GMX0_RX0_ADR_CAM3),
	_ENTRY(GMX0_RX0_ADR_CAM4),
	_ENTRY(GMX0_RX0_ADR_CAM5),
	_ENTRY(GMX0_TX0_CLK),
	_ENTRY(GMX0_TX0_THRESH),
	_ENTRY(GMX0_TX0_APPEND),
	_ENTRY(GMX0_TX0_SLOT),
	_ENTRY(GMX0_TX0_BURST),
	_ENTRY(GMX0_TX0_PAUSE_PKT_TIME),
	_ENTRY(GMX0_TX0_MIN_PKT),
	_ENTRY(GMX0_TX0_PAUSE_PKT_INTERVAL),
	_ENTRY(GMX0_TX0_SOFT_PAUSE),
	_ENTRY(GMX0_TX0_PAUSE_TOGO),
	_ENTRY(GMX0_TX0_PAUSE_ZERO),
	_ENTRY(GMX0_TX0_STATS_CTL),
	_ENTRY(GMX0_TX0_CTL),
};

const struct cn30xxgmx_dump_reg_ cn30xxgmx_dump_port_stats_[] = {
	_ENTRY(GMX0_RX0_STATS_PKTS),
	_ENTRY(GMX0_RX0_STATS_OCTS),
	_ENTRY(GMX0_RX0_STATS_PKTS_CTL),
	_ENTRY(GMX0_RX0_STATS_OCTS_CTL),
	_ENTRY(GMX0_RX0_STATS_PKTS_DMAC),
	_ENTRY(GMX0_RX0_STATS_OCTS_DMAC),
	_ENTRY(GMX0_RX0_STATS_PKTS_DRP),
	_ENTRY(GMX0_RX0_STATS_OCTS_DRP),
	_ENTRY(GMX0_RX0_STATS_PKTS_BAD),
	_ENTRY(GMX0_TX0_STAT0),
	_ENTRY(GMX0_TX0_STAT1),
	_ENTRY(GMX0_TX0_STAT2),
	_ENTRY(GMX0_TX0_STAT3),
	_ENTRY(GMX0_TX0_STAT4),
	_ENTRY(GMX0_TX0_STAT5),
	_ENTRY(GMX0_TX0_STAT6),
	_ENTRY(GMX0_TX0_STAT7),
	_ENTRY(GMX0_TX0_STAT8),
	_ENTRY(GMX0_TX0_STAT9),
};

void	cn30xxgmx_dump_common(void);
void	cn30xxgmx_dump_port0(void);
void	cn30xxgmx_dump_port1(void);
void	cn30xxgmx_dump_port2(void);
void	cn30xxgmx_dump_port0_regs(void);
void	cn30xxgmx_dump_port1_regs(void);
void	cn30xxgmx_dump_port2_regs(void);
void	cn30xxgmx_dump_port0_stats(void);
void	cn30xxgmx_dump_port1_stats(void);
void	cn30xxgmx_dump_port2_stats(void);
void	cn30xxgmx_dump_port_regs(int);
void	cn30xxgmx_dump_port_stats(int);
void	cn30xxgmx_dump_common_x(int, const struct cn30xxgmx_dump_reg_ *, size_t);
void	cn30xxgmx_dump_port_x(int, const struct cn30xxgmx_dump_reg_ *, size_t);
void	cn30xxgmx_dump_x(int, const struct cn30xxgmx_dump_reg_ *, size_t, size_t, int);
void	cn30xxgmx_dump_x_index(char *, size_t, int);

void
cn30xxgmx_dump(void)
{
	cn30xxgmx_dump_common();
	cn30xxgmx_dump_port0();
	cn30xxgmx_dump_port1();
	cn30xxgmx_dump_port2();
}

void
cn30xxgmx_dump_common(void)
{
	cn30xxgmx_dump_common_x(0, cn30xxgmx_dump_regs_,
	    nitems(cn30xxgmx_dump_regs_));
}

void
cn30xxgmx_dump_port0(void)
{
	cn30xxgmx_dump_port_regs(0);
	cn30xxgmx_dump_port_stats(0);
}

void
cn30xxgmx_dump_port1(void)
{
	cn30xxgmx_dump_port_regs(1);
	cn30xxgmx_dump_port_stats(1);
}

void
cn30xxgmx_dump_port2(void)
{
	cn30xxgmx_dump_port_regs(2);
	cn30xxgmx_dump_port_stats(2);
}

void
cn30xxgmx_dump_port_regs(int portno)
{
	cn30xxgmx_dump_port_x(portno, cn30xxgmx_dump_port_regs_,
	    nitems(cn30xxgmx_dump_port_regs_));
}

void
cn30xxgmx_dump_port_stats(int portno)
{
	struct cn30xxgmx_port_softc *sc = __cn30xxgmx_port_softc[0];
	uint64_t rx_stats_ctl;
	uint64_t tx_stats_ctl;

	rx_stats_ctl = _GMX_RD8(sc, GMX0_BASE_PORT_SIZE * portno + GMX0_RX0_STATS_CTL);
	_GMX_WR8(sc, GMX0_BASE_PORT_SIZE * portno + GMX0_RX0_STATS_CTL,
	    rx_stats_ctl & ~RXN_STATS_CTL_RD_CLR);
	tx_stats_ctl = _GMX_RD8(sc, GMX0_BASE_PORT_SIZE * portno + GMX0_TX0_STATS_CTL);
	_GMX_WR8(sc, GMX0_BASE_PORT_SIZE * portno + GMX0_TX0_STATS_CTL,
	    tx_stats_ctl & ~TXN_STATS_CTL_RD_CLR);
	cn30xxgmx_dump_port_x(portno, cn30xxgmx_dump_port_stats_,
	    nitems(cn30xxgmx_dump_port_stats_));
	_GMX_WR8(sc, GMX0_BASE_PORT_SIZE * portno + GMX0_RX0_STATS_CTL, rx_stats_ctl);
	_GMX_WR8(sc, GMX0_BASE_PORT_SIZE * portno + GMX0_TX0_STATS_CTL, tx_stats_ctl);
}

void
cn30xxgmx_dump_common_x(int portno, const struct cn30xxgmx_dump_reg_ *regs, size_t size)
{
	cn30xxgmx_dump_x(portno, regs, size, 0, 0);
}

void
cn30xxgmx_dump_port_x(int portno, const struct cn30xxgmx_dump_reg_ *regs, size_t size)
{
	cn30xxgmx_dump_x(portno, regs, size, GMX0_BASE_PORT_SIZE * portno, 1);
}

void
cn30xxgmx_dump_x(int portno, const struct cn30xxgmx_dump_reg_ *regs, size_t size, size_t base, int index)
{
	struct cn30xxgmx_port_softc *sc = __cn30xxgmx_port_softc[0];
	const struct cn30xxgmx_dump_reg_ *reg;
	uint64_t tmp;
	char name[64];
	int i;

	for (i = 0; i < (int)size; i++) {
		reg = &regs[i];
		tmp = _GMX_RD8(sc, base + reg->offset);

		snprintf(name, sizeof(name), "%s", reg->name);
		if (index > 0)
			cn30xxgmx_dump_x_index(name, sizeof(name), portno);

		printf("\t%-24s: %016llx\n", name, tmp);
	}
}

/* not in libkern */
static char *strstr(const char *, const char *);
static char *
strstr(const char *s, const char *find)
{
        char c, sc;
        size_t len;

        if ((c = *find++) != 0) {
                len = strlen(find);
                do {
                        do {
                                if ((sc = *s++) == 0)
                                        return (NULL);
                        } while (sc != c);
                } while (strncmp(s, find, len) != 0);
                s--;
        }
        return (char *)s;
}

void
cn30xxgmx_dump_x_index(char *buf, size_t len, int index)
{
	static const char *patterns[] = { "_TX0_", "_RX0_", "_PRT0_" };
	int i;

	for (i = 0; i < (int)nitems(patterns); i++) {
		char *p;

		p = strstr(buf, patterns[i]);
		if (p == NULL)
			continue;
		p = strchr(p, '0');
		KASSERT(p != NULL);
		*p = '0' + index;
		return;
	}
}

void
cn30xxgmx_debug_reset(void)
{
	int i;

	for (i = 0; i < 3; i++)
		cn30xxgmx_link_enable(__cn30xxgmx_port_softc[i], 0);
	for (i = 0; i < 3; i++)
		cn30xxgmx_link_enable(__cn30xxgmx_port_softc[i], 1);
}
#endif


code:
/*
 * THIS FILE IS AUTOMATICALLY GENERATED
 * DONT EDIT THIS FILE
 */

/*	$OpenBSD: cn30xxgmxreg.h,v 1.2 2014/08/11 18:29:56 miod Exp $	*/

/*
 * 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.
 */

/*
 * Cavium Networks OCTEON CN30XX Hardware Reference Manual
 * CN30XX-HM-1.0
 * 13.8 GMX Registers
 */

#ifndef _CN30XXGMXREG_H_
#define _CN30XXGMXREG_H_

#define	GMX0_RX0_INT_REG			0x000
#define	GMX0_RX0_INT_EN				0x008
#define	GMX0_PRT0_CFG				0x010
#define	GMX0_RX0_FRM_CTL			0x018
#define	GMX0_RX0_FRM_CHK			0x020
#define	GMX0_RX0_FRM_MIN			0x028
#define	GMX0_RX0_FRM_MAX			0x030
#define	GMX0_RX0_JABBER				0x038
#define	GMX0_RX0_DECISION			0x040
#define	GMX0_RX0_UDD_SKP			0x048
#define	GMX0_RX0_STATS_CTL			0x050
#define	GMX0_RX0_IFG				0x058
#define	GMX0_RX0_RX_INBND			0x060
#define	GMX0_RX0_STATS_PKTS			0x080
#define	GMX0_RX0_STATS_OCTS			0x088
#define	GMX0_RX0_STATS_PKTS_CTL			0x090
#define	GMX0_RX0_STATS_OCTS_CTL			0x098
#define	GMX0_RX0_STATS_PKTS_DMAC		0x0a0
#define	GMX0_RX0_STATS_OCTS_DMAC		0x0a8
#define	GMX0_RX0_STATS_PKTS_DRP			0x0b0
#define	GMX0_RX0_STATS_OCTS_DRP			0x0b8
#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_TX0_CLK				0x208
#define	GMX0_TX0_THRESH				0x210
#define	GMX0_TX0_APPEND				0x218
#define	GMX0_TX0_SLOT				0x220
#define	GMX0_TX0_BURST				0x228
#define	GMX0_SMAC0				0x230
#define	GMX0_TX0_PAUSE_PKT_TIME			0x238
#define	GMX0_TX0_MIN_PKT			0x240
#define	GMX0_TX0_PAUSE_PKT_INTERVAL		0x248
#define	GMX0_TX0_SOFT_PAUSE			0x250
#define	GMX0_TX0_PAUSE_TOGO			0x258
#define	GMX0_TX0_PAUSE_ZERO			0x260
#define	GMX0_TX0_STATS_CTL			0x268
#define	GMX0_TX0_CTL				0x270
#define	GMX0_TX0_STAT0				0x280
#define	GMX0_TX0_STAT1				0x288
#define	GMX0_TX0_STAT2				0x290
#define	GMX0_TX0_STAT3				0x298
#define	GMX0_TX0_STAT4				0x2a0
#define	GMX0_TX0_STAT5				0x2a8
#define	GMX0_TX0_STAT6				0x2b0
#define	GMX0_TX0_STAT7				0x2b8
#define	GMX0_TX0_STAT8				0x2c0
#define	GMX0_TX0_STAT9				0x2c8
#define	GMX0_BIST0				0x400
#define	GMX0_RX_PRTS				0x410
#define	GMX0_RX_BP_DROP0			0x420
#define	GMX0_RX_BP_DROP1			0x428
#define	GMX0_RX_BP_DROP2			0x430
#define	GMX0_RX_BP_ON0				0x440
#define	GMX0_RX_BP_ON1				0x448
#define	GMX0_RX_BP_ON2				0x450
#define	GMX0_RX_BP_OFF0				0x460
#define	GMX0_RX_BP_OFF1				0x468
#define	GMX0_RX_BP_OFF2				0x470
#define	GMX0_TX_PRTS				0x480
#define	GMX0_TX_IFG				0x488
#define	GMX0_TX_JAM				0x490
#define	GMX0_TX_COL_ATTEMPT			0x498
#define	GMX0_TX_PAUSE_PKT_DMAC			0x4a0
#define	GMX0_TX_PAUSE_PKT_TYPE			0x4a8
#define	GMX0_TX_OVR_BP				0x4c8
#define	GMX0_TX_BP				0x4d0
#define	GMX0_TX_CORRUPT				0x4d8
#define	GMX0_RX_PRT_INFO			0x4e8
#define	GMX0_TX_LFSR				0x4f8
#define	GMX0_TX_INT_REG				0x500
#define	GMX0_TX_INT_EN				0x508
#define	GMX0_NXA_ADR				0x510
#define	GMX0_BAD_REG				0x518
#define	GMX0_STAT_BP				0x520
#define	GMX0_TX_CLK_MSK0			0x780
#define	GMX0_TX_CLK_MSK1			0x788
#define	GMX0_RX_TX_STATUS			0x7e8
#define	GMX0_INF_MODE				0x7f8

/* -------------------------------------------------------------------------- */

/* GMX Interrupt Registers */

#define	RXN_INT_REG_XXX_63_19			0xfffffffffff80000ULL
#define	RXN_INT_REG_PHY_DUPX			0x0000000000040000ULL
#define	RXN_INT_REG_PHY_SPD			0x0000000000020000ULL
#define	RXN_INT_REG_PHY_LINK			0x0000000000010000ULL
#define	RXN_INT_REG_IFGERR			0x0000000000008000ULL
#define	RXN_INT_REG_COLDET			0x0000000000004000ULL
#define	RXN_INT_REG_FALERR			0x0000000000002000ULL
#define	RXN_INT_REG_RSVERR			0x0000000000001000ULL
#define	RXN_INT_REG_PCTERR			0x0000000000000800ULL
#define	RXN_INT_REG_OVRERR			0x0000000000000400ULL
#define	RXN_INT_REG_NIBERR			0x0000000000000200ULL
#define	RXN_INT_REG_SKPERR			0x0000000000000100ULL
#define	RXN_INT_REG_RCVERR			0x0000000000000080ULL
#define	RXN_INT_REG_LENERR			0x0000000000000040ULL
#define	RXN_INT_REG_ALNERR			0x0000000000000020ULL
#define	RXN_INT_REG_FCSERR			0x0000000000000010ULL
#define	RXN_INT_REG_JABBER			0x0000000000000008ULL
#define	RXN_INT_REG_MAXERR			0x0000000000000004ULL
#define	RXN_INT_REG_CAREXT			0x0000000000000002ULL
#define	RXN_INT_REG_MINERR			0x0000000000000001ULL

/* GMX Interrupt-Enable Registers */

#define	RXN_INT_EN_XXX_63_19			0xfffffffffff80000ULL
#define	RXN_INT_EN_PHY_DUPX			0x0000000000040000ULL
#define	RXN_INT_EN_PHY_SPD			0x0000000000020000ULL
#define	RXN_INT_EN_PHY_LINK			0x0000000000010000ULL
#define	RXN_INT_EN_IFGERR			0x0000000000008000ULL
#define	RXN_INT_EN_COLDET			0x0000000000004000ULL
#define	RXN_INT_EN_FALERR			0x0000000000002000ULL
#define	RXN_INT_EN_RSVERR			0x0000000000001000ULL
#define	RXN_INT_EN_PCTERR			0x0000000000000800ULL
#define	RXN_INT_EN_OVRERR			0x0000000000000400ULL
#define	RXN_INT_EN_NIBERR			0x0000000000000200ULL
#define	RXN_INT_EN_SKPERR			0x0000000000000100ULL
#define	RXN_INT_EN_RCVERR			0x0000000000000080ULL
#define	RXN_INT_EN_LENERR			0x0000000000000040ULL
#define	RXN_INT_EN_ALNERR			0x0000000000000020ULL
#define	RXN_INT_EN_FCSERR			0x0000000000000010ULL
#define	RXN_INT_EN_JABBER			0x0000000000000008ULL
#define	RXN_INT_EN_MAXERR			0x0000000000000004ULL
#define	RXN_INT_EN_CAREXT			0x0000000000000002ULL
#define	RXN_INT_EN_MINERR			0x0000000000000001ULL

/* GMX Port Configuration Registers */

#define	PRTN_CFG_XXX_63_4			0xfffffffffffffff0ULL
#define	PRTN_CFG_SLOTTIME			0x0000000000000008ULL
#define	PRTN_CFG_DUPLEX				0x0000000000000004ULL
#define	PRTN_CFG_SPEED				0x0000000000000002ULL
#define	PRTN_CFG_EN				0x0000000000000001ULL

/* Frame Control Registers */

#define	RXN_FRM_CTL_XXX_63_11			0xfffffffffffff800ULL
#define	RXN_FRM_CTL_NULL_DIS			0x0000000000000400ULL
#define	RXN_FRM_CTL_PRE_ALIGN			0x0000000000000200ULL
#define	RXN_FRM_CTL_PAD_LEN			0x0000000000000100ULL
#define	RXN_FRM_CTL_VLAN_LEN			0x0000000000000080ULL
#define	RXN_FRM_CTL_PRE_FREE			0x0000000000000040ULL
#define	RXN_FRM_CTL_CTL_SMAC			0x0000000000000020ULL
#define	RXN_FRM_CTL_CTL_MCST			0x0000000000000010ULL
#define	RXN_FRM_CTL_CTL_BCK			0x0000000000000008ULL
#define	RXN_FRM_CTL_CTL_DRP			0x0000000000000004ULL
#define	RXN_FRM_CTL_PRE_STRP			0x0000000000000002ULL
#define	RXN_FRM_CTL_PRE_CHK			0x0000000000000001ULL

/* Frame Check Registers */

#define RXN_FRM_CKK_XXX_63_10			0xfffffffffffffc00ULL
#define	RXN_FRM_CHK_NIBERR			0x0000000000000200ULL
#define	RXN_FRM_CHK_SKPERR			0x0000000000000100ULL
#define	RXN_FRM_CHK_RCVERR			0x0000000000000080ULL
#define	RXN_FRM_CHK_LENERR			0x0000000000000040ULL
#define	RXN_FRM_CHK_ALNERR			0x0000000000000020ULL
#define	RXN_FRM_CHK_FCSERR			0x0000000000000010ULL
#define	RXN_FRM_CHK_JABBER			0x0000000000000008ULL
#define	RXN_FRM_CHK_MAXERR			0x0000000000000004ULL
#define	RXN_FRM_CHK_CAREXT			0x0000000000000002ULL
#define	RXN_FRM_CHK_MINERR			0x0000000000000001ULL

/* Frame Minimum-Length Registers */

#define	RXN_RRM_MIN_XXX_63_16			0xffffffffffff0000ULL
#define	RXN_RRM_MIN_LEN				0x000000000000ffffULL

/* Frame Maximun-Length Registers */

#define	RXN_RRM_MAX_XXX_63_16			0xffffffffffff0000ULL
#define	RXN_RRM_MAX_LEN				0x000000000000ffffULL

/* GMX Maximun Packet-Size Registers */

#define	RXN_JABBER_XXX_63_16			0xffffffffffff0000ULL
#define	RXN_JABBER_CNT				0x000000000000ffffULL

/* GMX Packet Decision Registers */

#define	RXN_DECISION_XXX_63_5			0xffffffffffffffe0ULL
#define	RXN_DECISION_CNT			0x000000000000001fULL

/* GMX User-Defined Data Skip Registers */

#define	RXN_UDD_SKP_XXX_63_9			0xfffffffffffffe00ULL
#define	RXN_UDD_SKP_FCSSEL			0x0000000000000100ULL
#define	RXN_UDD_SKP_XXX_7			0x0000000000000080ULL
#define	RXN_UDD_SKP_LEN				0x000000000000007fULL

/* GMX RX Statistics Control Registers */

#define	RXN_STATS_CTL_XXX_63_1			0xfffffffffffffffeULL
#define	RXN_STATS_CTL_RD_CLR			0x0000000000000001ULL

/* GMX Minimun Interface-Gap Cycles Registers */

#define	RXN_IFG_XXX_63_4			0xfffffffffffffff0ULL
#define	RXN_IFG_IFG				0x000000000000000fULL

/* InBand Link Status Registers */

#define	RXN_RX_INBND_XXX_63_4			0xfffffffffffffff0ULL
#define	RXN_RX_INBND_DUPLEX			0x0000000000000008ULL
#define	 RXN_RX_INBND_DUPLEX_SHIFT		3
#define	  RXN_RX_INBND_DUPLEX_HALF		(0ULL << RXN_RX_INBND_DUPLEX_SHIFT)
#define	  RXN_RX_INBND_DUPLEX_FULL		(1ULL << RXN_RX_INBND_DUPLEX_SHIFT)
#define	RXN_RX_INBND_SPEED			0x0000000000000006ULL
#define	 RXN_RX_INBND_SPEED_SHIFT		1
#define	  RXN_RX_INBND_SPEED_2_5		(0ULL << RXN_RX_INBND_SPEED_SHIFT)
#define	  RXN_RX_INBND_SPEED_25			(1ULL << RXN_RX_INBND_SPEED_SHIFT)
#define	  RXN_RX_INBND_SPEED_125		(2ULL << RXN_RX_INBND_SPEED_SHIFT)
#define	  RXN_RX_INBND_SPEED_XXX_3		(3ULL << RXN_RX_INBND_SPEED_SHIFT)
#define	RXN_RX_INBND_STATUS			0x0000000000000001ULL

/* GMX RX Good Packets Registers */

#define	RXN_STATS_PKTS_XXX_63_32		0xffffffff00000000ULL
#define	RXN_STATS_PKTS_CNT			0x00000000ffffffffULL

/* GMX RX Good Packets Octet Registers */

#define	RXN_STATS_OCTS_XXX_63_48		0xffff000000000000ULL
#define	RXN_STATS_OCTS_CNT			0x0000ffffffffffffULL

/* GMX RX Pause Packets Registers */

#define	RXN_STATS_PKTS_CTL_XXX_63_32		0xffffffff00000000ULL
#define	RXN_STATS_PKTS_CTL_CNT			0x00000000ffffffffULL

/* GMX RX Pause Packets Octet Registers */

#define	RXN_STATS_OCTS_CTL_XXX_63_48		0xffff000000000000ULL
#define	RXN_STATS_OCTS_CTL_CNT			0x0000ffffffffffffULL

/* GMX RX DMAC Packets Registers */

#define	RXN_STATS_PKTS_DMAC_XXX_63_32		0xffffffff00000000ULL
#define	RXN_STATS_PKTS_DMAC_CNT			0x00000000ffffffffULL

/* GMX RX DMAC Packets Octet Registers */

#define	RXN_STATS_OCTS_DMAC_XXX_63_48		0xffff000000000000ULL
#define	RXN_STATS_OCTS_DMAC_CNT			0x0000ffffffffffffULL

/* GMX RX Overflow Packets Registers */

#define	RXN_STATS_PKTS_DRP_XXX_63_48		0xffffffff00000000ULL
#define	RXN_STATS_PKTS_DRP_CNT			0x00000000ffffffffULL

/* GMX RX Overflow Packets Octet Registers */

#define	RXN_STATS_OCTS_DRP_XXX_63_48		0xffff000000000000ULL
#define	RXN_STATS_OCTS_DRP_CNT			0x0000ffffffffffffULL

/* GMX RX Bad Packets Registers */

#define	RXN_STATS_PKTS_BAD_XXX_63_48		0xffffffff00000000ULL
#define	RXN_STATS_PKTS_BAD_CNT			0x00000000ffffffffULL

/* Address-Filtering Control Registers */

#define	RXN_ADR_CTL_XXX_63_4			0xfffffffffffffff0ULL
#define	RXN_ADR_CTL_CAM_MODE			0x0000000000000008ULL
#define	 RXN_ADR_CTL_CAM_MODE_SHIFT		3
#define	  RXN_ADR_CTL_CAM_MODE_REJECT		(0ULL << RXN_ADR_CTL_CAM_MODE_SHIFT)
#define	  RXN_ADR_CTL_CAM_MODE_ACCEPT		(1ULL << RXN_ADR_CTL_CAM_MODE_SHIFT)
#define	RXN_ADR_CTL_MCST			0x0000000000000006ULL
#define	 RXN_ADR_CTL_MCST_SHIFT			1
#define	  RXN_ADR_CTL_MCST_AFCAM		(0ULL << RXN_ADR_CTL_MCST_SHIFT)
#define	  RXN_ADR_CTL_MCST_REJECT		(1ULL << RXN_ADR_CTL_MCST_SHIFT)
#define	  RXN_ADR_CTL_MCST_ACCEPT		(2ULL << RXN_ADR_CTL_MCST_SHIFT)
#define	  RXN_ADR_CTL_MCST_XXX_3		(3ULL << RXN_ADR_CTL_MCST_SHIFT)
#define	RXN_ADR_CTL_BCST			0x0000000000000001ULL

/* Address-Filtering Control Enable Registers */

#define	RXN_ADR_CAM_EN_XXX_63_8			0xffffffffffffff00ULL
#define	RXN_ADR_CAM_EN_EN			0x00000000000000ffULL

/* Address-Filtering CAM Control Registers */
#define	RXN_ADR_CAMN_ADR			0xffffffffffffffffULL

/* GMX TX Clock Generation Registers */

#define	TXN_CLK_XXX_63_6			0xffffffffffffffc0ULL
#define	TXN_CLK_CLK_CNT				0x000000000000003fULL

/* TX Threshold Registers */

#define	TXN_THRESH_XXX_63_6			0xffffffffffffffc0ULL
#define	TXN_THRESH_CNT				0x000000000000003fULL

/* TX Append Control Registers */

#define	TXN_APPEND_XXX_63_4			0xfffffffffffffff0ULL
#define	TXN_APPEND_FORCE_FCS			0x0000000000000008ULL
#define	TXN_APPEND_FCS				0x0000000000000004ULL
#define	TXN_APPEND_PAD				0x0000000000000002ULL
#define	TXN_APPEND_PREAMBLE			0x0000000000000001ULL

/* TX Slottime Counter Registers */

#define	TXN_SLOT_XXX_63_10			0xfffffffffffffc00ULL
#define	TXN_SLOT_SLOT				0x00000000000003ffULL

/* TX Burst-Counter Registers */

#define	TXN_BURST_XXX_63_16			0xffffffffffff0000ULL
#define	TXN_BURST_BURST				0x000000000000ffffULL

/* RGMII SMAC Registers */

#define	SMACN_XXX_63_48				0xffff000000000000ULL
#define	SMACN_SMAC				0x0000ffffffffffffULL

/* TX Pause Packet Pause-Time Registers */

#define	TXN_PAUSE_PKT_TIME_XXX_63_16		0xffffffffffff0000ULL
#define	TXN_PAUSE_PKT_TIME_TIME			0x000000000000ffffULL

/* RGMII TX Minimum-Size-Packet Registers */

#define	TXN_MIN_PKT_XXX_63_8			0xffffffffffffff00ULL
#define	TXN_MIN_PKT_MIN_SIZE			0x00000000000000ffULL

/* TX Pause-Packet Transmission-Interval Registers */

#define	TXN_PAUSE_PKT_INTERVAL_XXX_63_16	0xffffffffffff0000ULL
#define	TXN_PAUSE_PKT_INTERVAL_INTERVAL		0x000000000000ffffULL

/* TX Software-Pause Registers */

#define	TXN_SOFT_PAUSE_XXX_63_16		0xffffffffffff0000ULL
#define	TXN_SOFT_PAUSE_TIME			0x000000000000ffffULL

/* TX Time-to-Backpressure Registers */

#define	TXN_PAUSE_TOGO_XXX_63_16		0xffffffffffff0000ULL
#define	TXN_PAUSE_TOGO_TIME			0x000000000000ffffULL

/* TX Pause-Zero-Enable Registers */

#define	TXN_PAUSE_ZERO_XXX_63_1			0xfffffffffffffffeULL
#define	TXN_PAUSE_ZERO_SEND			0x0000000000000001ULL

/* GMX TX Statistics Control Registers */

#define	TXN_STATS_CTL_XXX_63_1			0xfffffffffffffffeULL
#define	TXN_STATS_CTL_RD_CLR			0x0000000000000001ULL

/* GMX TX Transmit Control Registers */

#define	TXN_CTL_XXX_63_2			0xfffffffffffffffcULL
#define	TXN_CTL_XSDEF_EN			0x0000000000000002ULL
#define	TXN_CTL_XSCOL_EN			0x0000000000000001ULL

/* Transmit Statistics Registers 0 */

#define	TXN_STAT0_XSDEF				0xffffffff00000000ULL
#define	TXN_STAT0_XSCOL				0x00000000ffffffffULL

/* Transmit Statistics Registers 1 */

#define	TXN_STAT1_SCOL				0xffffffff00000000ULL
#define	TXN_STAT1_MSCOL				0x00000000ffffffffULL

/* Transmit Statistics Registers 2 */

#define	TXN_STAT2_XXX_63_48			0xffff000000000000ULL
#define	TXN_STAT2_OCTS				0x0000ffffffffffffULL

/* Transmit Statistics Registers 3 */

#define	TXN_STAT3_XXX_63_48			0xffffffff00000000ULL
#define	TXN_STAT3_PKTS				0x00000000ffffffffULL

/* Transmit Statistics Registers 4 */

#define	TXN_STAT4_HIST1				0xffffffff00000000ULL
#define	TXN_STAT4_HIST0				0x00000000ffffffffULL

/* Transmit Statistics Registers 5 */

#define	TXN_STAT5_HIST3				0xffffffff00000000ULL
#define	TXN_STAT5_HIST2				0x00000000ffffffffULL

/* Transmit Statistics Registers 6 */

#define	TXN_STAT6_HIST5				0xffffffff00000000ULL
#define	TXN_STAT6_HIST4				0x00000000ffffffffULL

/* Transmit Statistics Registers 7 */

#define	TXN_STAT7_HIST7				0xffffffff00000000ULL
#define	TXN_STAT7_HIST6				0x00000000ffffffffULL

/* Transmit Statistics Registers 8 */

#define	TXN_STAT8_MCST				0xffffffff00000000ULL
#define	TXN_STAT8_BCST				0x00000000ffffffffULL

/* Transmit Statistics Register 9 */

#define	TXN_STAT9_UNDFLW			0xffffffff00000000ULL
#define	TXN_STAT9_CTL				0x00000000ffffffffULL

/* BMX BIST Results Register */

#define	BIST_XXX_63_10				0xfffffffffffffc00ULL
#define	BIST_STATUS				0x00000000000003ffULL

/* RX Ports Register */

#define	RX_PRTS_XXX_63_3			0xfffffffffffffff8ULL
#define	RX_PRTS_PRTS				0x0000000000000007ULL

/* RX FIFO Packet-Drop Registers */

#define	RX_BP_DROPN_XXX_63_6			0xffffffffffffffc0ULL
#define	RX_BP_DROPN_MARK			0x000000000000003fULL

/* RX Backpressure On Registers */

#define	RX_BP_ONN_XXX_63_9			0xfffffffffffffe00ULL
#define	RX_BP_ONN_MARK				0x00000000000001ffULL

/* RX Backpressure Off Registers */

#define	RX_BP_OFFN_XXX_63_6			0xffffffffffffffc0ULL
#define	RX_BP_OFFN_MARK				0x000000000000003fULL

/* TX Ports Register */

#define	TX_PRTS_XXX_63_5			0xffffffffffffffe0ULL
#define	TX_PRTS_PRTS				0x000000000000001fULL

/* TX Interframe Gap Register */

#define	TX_IFG_XXX_63_8				0xffffffffffffff00ULL
#define	TX_IFG_IFG2				0x00000000000000f0ULL
#define	TX_IFG_IFG1				0x000000000000000fULL

/* TX Jam Pattern Register */

#define	TX_JAM_XXX_63_8				0xffffffffffffff00ULL
#define	TX_JAM_JAM				0x00000000000000ffULL

/* TX Collision Attempts Before Dropping Frame Register */

#define	TX_COL_ATTEMPT_XXX_63_5			0xffffffffffffffe0ULL
#define	TX_COL_ATTEMPT_LIMIT			0x000000000000001fULL

/* TX Pause-Packet DMAC-Field Register */

#define	TX_PAUSE_PKT_DMAC_XXX_63_48		0xffff000000000000ULL
#define	TX_PAUSE_PKT_DMAC_DMAC			0x0000ffffffffffffULL

/* TX Pause Packet Type Field Register */

#define	TX_PAUSE_PKT_TYPE_XXX_63_16		0xffffffffffff0000ULL
#define	TX_PAUSE_PKT_TYPE_TYPE			0x000000000000ffffULL

/* TX Override Backpressure Register */

#define	TX_OVR_BP_XXX_63_12			0xfffffffffffff000ULL
#define	TX_OVR_BP_XXX_11			0x0000000000000800ULL
#define	TX_OVR_BP_EN				0x0000000000000700ULL
#define	 TX_OVR_BP_EN_SHIFT			8
#define	TX_OVR_BP_XXX_7				0x0000000000000080ULL
#define	TX_OVR_BP_BP				0x0000000000000070ULL
#define	 TX_OVR_BP_BP_SHIFT			4
#define	TX_OVR_BP_XXX_3				0x0000000000000008ULL
#define	TX_OVR_BP_IGN_FULL			0x0000000000000007ULL
#define	 TX_OVR_BP_IGN_FULL_SHIFT		0

/* TX Override Backpressure Register */

#define	TX_OVR_BP_XXX_63_12			0xfffffffffffff000ULL
#define	TX_OVR_BP_XXX_11			0x0000000000000800ULL
#define	TX_OVR_BP_EN				0x0000000000000700ULL
#define	TX_OVR_BP_XXX_7				0x0000000000000080ULL
#define	TX_OVR_BP_BP				0x0000000000000070ULL
#define	TX_OVR_BP_XXX_3				0x0000000000000008ULL
#define	TX_OVR_BP_IGN_FULL			0x0000000000000007ULL

/* TX Backpressure Status Register */

#define	TX_BP_SR_XXX_63_3			0xfffffffffffffff8ULL
#define	TX_BP_SR_BP				0x0000000000000007ULL

/* TX Corrupt Packets Register */

#define	TX_CORRUPT_XXX_63_3			0xfffffffffffffff8ULL
#define	TX_CORRUPT_CORRUPT			0x0000000000000007ULL

/* RX Port State Information Register */

#define	RX_PRT_INFO_XXX_63_19			0xfffffffffff80000ULL
#define	RX_PRT_INFO_DROP			0x0000000000070000ULL
#define	RX_PRT_INFO_XXX_15_3			0x000000000000fff8ULL
#define	RX_PRT_INFO_COMMIT			0x0000000000000007ULL

/* TX LFSR Register */

#define	TX_LFSR_XXX_63_16			0xffffffffffff0000ULL
#define	TX_LFSR_LFSR				0x000000000000ffffULL

/* TX Interrupt Register */

#define	TX_INT_REG_XXX_63_20			0xfffffffffff00000ULL
#define	TX_INT_REG_XXX_19			0x0000000000080000ULL
#define	TX_INT_REG_LATE_COL			0x0000000000070000ULL
#define	TX_INT_REG_XXX_15			0x0000000000008000ULL
#define	TX_INT_REG_XSDEF			0x0000000000007000ULL
#define	TX_INT_REG_XXX_11			0x0000000000000800ULL
#define	TX_INT_REG_XSCOL			0x0000000000000700ULL
#define	TX_INT_REG_XXX_7_5			0x00000000000000e0ULL
#define	TX_INT_REG_UNDFLW			0x000000000000001cULL
#define	TX_INT_REG_XXX_1			0x0000000000000002ULL
#define	TX_INT_REG_PKO_NXA			0x0000000000000001ULL

/* TX Interrupt Register */

#define	TX_INT_EN_XXX_63_20			0xfffffffffff00000ULL
#define	TX_INT_EN_XXX_19			0x0000000000080000ULL
#define	TX_INT_EN_LATE_COL			0x0000000000070000ULL
#define	TX_INT_EN_XXX_15			0x0000000000008000ULL
#define	TX_INT_EN_XSDEF				0x0000000000007000ULL
#define	TX_INT_EN_XXX_11			0x0000000000000800ULL
#define	TX_INT_EN_XSCOL				0x0000000000000700ULL
#define	TX_INT_EN_XXX_7_5			0x00000000000000e0ULL
#define	TX_INT_EN_UNDFLW			0x000000000000001cULL
#define	TX_INT_EN_XXX_1				0x0000000000000002ULL
#define	TX_INT_EN_PKO_NXA			0x0000000000000001ULL

/* Address-out-of-Range Error Register */

#define	NXA_ADR_XXX_63_6			0xffffffffffffffc0ULL
#define	NXA_ADR_PRT				0x000000000000003fULL

/* GMX Miscellaneous Error Register */

#define	BAD_REG_XXX_63_31			0xffffffff80000000ULL
#define	BAD_REG_INB_NXA				0x0000000078000000ULL
#define	BAD_REG_STATOVR				0x0000000004000000ULL
#define	BAD_REG_XXX_25				0x0000000002000000ULL
#define	BAD_REG_LOSTSTAT			0x0000000001c00000ULL
#define	BAD_REG_XXX_21_18			0x00000000003c0000ULL
#define	BAD_REG_XXX_17_5			0x000000000003ffe0ULL
#define	BAD_REG_OUT_OVR				0x000000000000001cULL
#define	BAD_REG_XXX_1_0				0x0000000000000003ULL

/* GMX Backpressure Statistics Register */

#define	STAT_BP_XXX_63_17			0xfffffffffffe0000ULL
#define	STAT_BP_BP				0x0000000000010000ULL
#define	STAT_BP_CNT				0x000000000000ffffULL

/* Mode Change Mask Registers */

#define	TX_CLK_MSKN_XXX_63_1			0xfffffffffffffffeULL
#define	TX_CLK_MSKN_MSK				0x0000000000000001ULL

/* GMX RX/TX Status Register */

#define	RX_TX_STATUS_XXX_63_7			0xffffffffffffff80ULL
#define	RX_TX_STATUS_TX				0x0000000000000070ULL
#define	RX_TX_STATUS_XXX_3			0x0000000000000008ULL
#define	RX_TX_STATUS_RX				0x0000000000000007ULL

/* Interface Mode Register */

#define	INF_MODE_XXX_63_3			0xfffffffffffffff8ULL
#define	INF_MODE_P0MII				0x0000000000000004ULL
#define	INF_MODE_EN				0x0000000000000002ULL
#define	INF_MODE_TYPE				0x0000000000000001ULL

/* -------------------------------------------------------------------------- */

/* for bus_space(9) */

#define GMX_IF_NUNITS				1
#define GMX_PORT_NUNITS				3

#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)

#endif /* _CN30XXGMXREG_H_ */

license: unknown


code:
/*	$OpenBSD: cn30xxgmxvar.h,v 1.4 2014/08/11 18:52:54 miod Exp $	*/

/*
 * 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.
 */

#ifndef _CN30XXGMXVAR_H_
#define _CN30XXGMXVAR_H_

#include <sys/socket.h>
#include <net/if.h>
#include <net/if_media.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>

#define GMX_MII_PORT	1
#define GMX_GMII_PORT	2
#define GMX_RGMII_PORT	3
#define GMX_SPI42_PORT	4

#define GMX_FRM_MAX_SIZ	0x600

/* Disable 802.3x flow-control when AutoNego is enabled */
#define GMX_802_3X_DISABLE_AUTONEG

struct cn30xxgmx_softc;
struct cn30xxgmx_port_softc;

struct cn30xxgmx_port_softc {
	struct cn30xxgmx_softc	*sc_port_gmx;
	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;
	struct cn30xxgmx_port_ops
				*sc_port_ops;
	struct cn30xxasx_softc	*sc_port_asx;
	struct cn30xxipd_softc	*sc_ipd;
	int			sc_port_flowflags;
};

struct cn30xxgmx_softc {
	struct device		sc_dev;

	bus_space_tag_t		sc_regt;
	bus_space_handle_t	sc_regh;
	int			sc_unitno;	/* GMX0, GMX1, ... */
	int			sc_nports;
	int			sc_port_types[4/* XXX */];

	struct cn30xxgmx_port_softc
				*sc_ports;
};

struct cn30xxgmx_attach_args {
        bus_space_tag_t         ga_regt;
	bus_addr_t		ga_addr;
	bus_dma_tag_t		ga_dmat;
	const char		*ga_name;
	int			ga_portno;
	int			ga_port_type;
	int			ga_phy_addr;

	struct cn30xxgmx_softc *ga_gmx;
	struct cn30xxgmx_port_softc
				*ga_gmx_port;
};

#define	CN30XXGMX_FILTER_NADDRS_MAX	8	/* XXX elsewhere */

enum CN30XXGMX_FILTER_POLICY {
	CN30XXGMX_FILTER_POLICY_ACCEPT_ALL,
	CN30XXGMX_FILTER_POLICY_ACCEPT,
	CN30XXGMX_FILTER_POLICY_REJECT,
	CN30XXGMX_FILTER_POLICY_REJECT_ALL
};

int		cn30xxgmx_link_enable(struct cn30xxgmx_port_softc *, int);
int		cn30xxgmx_tx_stats_rd_clr(struct cn30xxgmx_port_softc *, int);
int		cn30xxgmx_rx_stats_rd_clr(struct cn30xxgmx_port_softc *, int);
void		cn30xxgmx_rx_stats_dec_bad(struct cn30xxgmx_port_softc *);
int		cn30xxgmx_stats_init(struct cn30xxgmx_port_softc *);
void		cn30xxgmx_tx_int_enable(struct cn30xxgmx_port_softc *, int);
void		cn30xxgmx_rx_int_enable(struct cn30xxgmx_port_softc *, int);
int		cn30xxgmx_setfilt(struct cn30xxgmx_port_softc *,
		    enum CN30XXGMX_FILTER_POLICY, size_t, uint8_t **);
int		cn30xxgmx_rx_frm_ctl_enable(struct cn30xxgmx_port_softc *,
		    uint64_t rx_frm_ctl);
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 *);
int		cn30xxgmx_reset_flowctl(struct cn30xxgmx_port_softc *);
int		cn30xxgmx_reset_timing(struct cn30xxgmx_port_softc *);
int		cn30xxgmx_reset_board(struct cn30xxgmx_port_softc *);
void		cn30xxgmx_stats(struct cn30xxgmx_port_softc *);
uint64_t	cn30xxgmx_get_rx_int_reg(struct cn30xxgmx_port_softc *sc);
uint64_t	cn30xxgmx_get_tx_int_reg(struct cn30xxgmx_port_softc *sc);
static inline int	cn30xxgmx_link_status(struct cn30xxgmx_port_softc *);

/* XXX RGMII specific */
static inline int
cn30xxgmx_link_status(struct cn30xxgmx_port_softc *sc)
{
	return (sc->sc_link & RXN_RX_INBND_STATUS) ? 1 : 0;
}

#endif


code:
/*	$OpenBSD: cn30xxipd.c,v 1.5 2014/08/11 18:29:56 miod Exp $	*/

/*
 * 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 <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>

#include <machine/octeonvar.h>

#include <octeon/dev/cn30xxciureg.h>
#include <octeon/dev/cn30xxfpavar.h>
#include <octeon/dev/cn30xxpipreg.h>
#include <octeon/dev/cn30xxipdreg.h>
#include <octeon/dev/cn30xxipdvar.h>

#include <netinet/in.h>

#define IP_OFFSET(data, word2) \
	((caddr_t)(data) + ((word2 & PIP_WQE_WORD2_IP_OFFSET) >> PIP_WQE_WORD2_IP_OFFSET_SHIFT))

#ifdef OCTEON_ETH_DEBUG
void	cn30xxipd_intr_rml(void *);
int	cn30xxipd_intr_drop(void *);

void	cn30xxipd_dump(void);

void	*cn30xxipd_intr_drop_ih;

struct cn30xxipd_softc	*__cn30xxipd_softc[3/* XXX */];
#endif

/* XXX */
void
cn30xxipd_init(struct cn30xxipd_attach_args *aa,
    struct cn30xxipd_softc **rsc)
{
	struct cn30xxipd_softc *sc;
	int status;

	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
	if (sc == NULL)
		panic("can't allocate memory: %s", __func__);

	sc->sc_port = aa->aa_port;
	sc->sc_regt = aa->aa_regt;
	sc->sc_first_mbuff_skip = aa->aa_first_mbuff_skip;
	sc->sc_not_first_mbuff_skip = aa->aa_not_first_mbuff_skip;

	status = bus_space_map(sc->sc_regt, IPD_BASE, IPD_SIZE, 0,
	    &sc->sc_regh);
	if (status != 0)
		panic("can't map %s space", "ipd register");

	*rsc = sc;

#ifdef OCTEON_ETH_DEBUG
	cn30xxipd_int_enable(sc, 1);
	if (cn30xxipd_intr_drop_ih == NULL)
		cn30xxipd_intr_drop_ih = octeon_intr_establish(
		   ffs64(CIU_INTX_SUM0_IPD_DRP) - 1, IPL_NET,
		   cn30xxipd_intr_drop, NULL, "cn30xxipd");
	__cn30xxipd_softc[sc->sc_port] = sc;
#endif /* OCTEON_ETH_DEBUG */
}

#define	_IPD_RD8(sc, off) \
	bus_space_read_8((sc)->sc_regt, (sc)->sc_regh, (off))
#define	_IPD_WR8(sc, off, v) \
	bus_space_write_8((sc)->sc_regt, (sc)->sc_regh, (off), (v))

int
cn30xxipd_enable(struct cn30xxipd_softc *sc)
{
	uint64_t ctl_status;

	ctl_status = _IPD_RD8(sc, IPD_CTL_STATUS_OFFSET);
	SET(ctl_status, IPD_CTL_STATUS_IPD_EN);
	_IPD_WR8(sc, IPD_CTL_STATUS_OFFSET, ctl_status);

	return 0;
}

int
cn30xxipd_config(struct cn30xxipd_softc *sc)
{
	uint64_t first_mbuff_skip;
	uint64_t not_first_mbuff_skip;
	uint64_t packet_mbuff_size;
	uint64_t first_next_ptr_back;
	uint64_t second_next_ptr_back;
	uint64_t sqe_fpa_queue;
	uint64_t ctl_status;

	/* XXX */
	first_mbuff_skip = 0;
	SET(first_mbuff_skip, (sc->sc_first_mbuff_skip / 8) & IPD_1ST_MBUFF_SKIP_SZ);
	_IPD_WR8(sc, IPD_1ST_MBUFF_SKIP_OFFSET, first_mbuff_skip);
	/* XXX */

	/* XXX */
	not_first_mbuff_skip = 0;
	SET(not_first_mbuff_skip, (sc->sc_not_first_mbuff_skip / 8) &
	    IPD_NOT_1ST_MBUFF_SKIP_SZ);
	_IPD_WR8(sc, IPD_NOT_1ST_MBUFF_SKIP_OFFSET, not_first_mbuff_skip);
	/* XXX */

	packet_mbuff_size = 0;
	SET(packet_mbuff_size, (FPA_RECV_PKT_POOL_SIZE / 8) &
	    IPD_PACKET_MBUFF_SIZE_MB_SIZE);
	_IPD_WR8(sc, IPD_PACKET_MBUFF_SIZE_OFFSET, packet_mbuff_size);

	first_next_ptr_back = 0;
	SET(first_next_ptr_back, (sc->sc_first_mbuff_skip / 128) & IPD_1ST_NEXT_PTR_BACK_BACK);
	_IPD_WR8(sc, IPD_1ST_NEXT_PTR_BACK_OFFSET, first_next_ptr_back);

	second_next_ptr_back = 0;
	SET(second_next_ptr_back, (sc->sc_not_first_mbuff_skip / 128) &
	    IPD_2ND_NEXT_PTR_BACK_BACK);
	_IPD_WR8(sc, IPD_2ND_NEXT_PTR_BACK_OFFSET, second_next_ptr_back);

	sqe_fpa_queue = 0;
	SET(sqe_fpa_queue, FPA_WQE_POOL & IPD_WQE_FPA_QUEUE_WQE_QUE);
	_IPD_WR8(sc, IPD_WQE_FPA_QUEUE_OFFSET, sqe_fpa_queue);

	ctl_status = _IPD_RD8(sc, IPD_CTL_STATUS_OFFSET);
	CLR(ctl_status, IPD_CTL_STATUS_OPC_MODE);
	SET(ctl_status, IPD_CTL_STATUS_OPC_MODE_ALL);
	SET(ctl_status, IPD_CTL_STATUS_PBP_EN);

	_IPD_WR8(sc, IPD_CTL_STATUS_OFFSET, ctl_status);

	return 0;
}

/*
 * octeon work queue entry offload
 * L3 error & L4 error
 */
void
cn30xxipd_offload(uint64_t word2, caddr_t data, uint16_t *rcflags)
{
#if 0 /* XXX */
	int cflags;

	if (ISSET(word2, PIP_WQE_WORD2_IP_NI))
		return;

	cflags = 0;

	if (!ISSET(word2, PIP_WQE_WORD2_IP_V6))
		SET(cflags, M_CSUM_IPv4);

	if (ISSET(word2, PIP_WQE_WORD2_IP_TU)) {
		SET(cflags,
		    !ISSET(word2, PIP_WQE_WORD2_IP_V6) ?
		    (M_CSUM_TCPv4 | M_CSUM_UDPv4) :
		    (M_CSUM_TCPv6 | M_CSUM_UDPv6));
	}

	/* check L3 (IP) error */
	if (ISSET(word2, PIP_WQE_WORD2_IP_IE)) {
		struct ip *ip;

		switch (word2 & PIP_WQE_WORD2_IP_OPECODE) {
		case IPD_WQE_L3_V4_CSUM_ERR:
			/* CN31XX_Pass_1.1_Issues_v1.5 2.4.5.1 */
			ip = (struct ip *)(IP_OFFSET(data, word2));
			if (ip->ip_hl == 5)
				SET(cflags, M_CSUM_IPv4_BAD);
			break;
		default:
			break;
		}
	}

	/* check L4 (UDP / TCP) error */
	if (ISSET(word2, PIP_WQE_WORD2_IP_LE)) {
		switch (word2 & PIP_WQE_WORD2_IP_OPECODE) {
		case IPD_WQE_L4_CSUM_ERR:
			SET(cflags, M_CSUM_TCP_UDP_BAD);
			break;
		default:
			break;
		}
	}

	*rcflags = cflags;
#endif
}

void
cn30xxipd_sub_port_fcs(struct cn30xxipd_softc *sc, int enable)
{
	uint64_t sub_port_fcs;

	sub_port_fcs = _IPD_RD8(sc, IPD_SUB_PORT_FCS_OFFSET);
	if (enable == 0)
		CLR(sub_port_fcs, 1 << sc->sc_port);
	else
		SET(sub_port_fcs, 1 << sc->sc_port);
	_IPD_WR8(sc, IPD_SUB_PORT_FCS_OFFSET, sub_port_fcs);
}

#ifdef OCTEON_ETH_DEBUG
int	cn30xxipd_intr_rml_verbose;

void
cn30xxipd_intr_rml(void *arg)
{
	int i;

	for (i = 0; i < 3/* XXX */; i++) {
		struct cn30xxipd_softc *sc;
		uint64_t reg;

		sc = __cn30xxipd_softc[i];
		KASSERT(sc != NULL);
		reg = cn30xxipd_int_summary(sc);
		if (cn30xxipd_intr_rml_verbose)
			printf("%s: IPD_INT_SUM=0x%016llx\n", __func__, reg);
	}
}

void
cn30xxipd_int_enable(struct cn30xxipd_softc *sc, int enable)
{
	uint64_t ipd_int_xxx = 0;

	SET(ipd_int_xxx,
	    IPD_INT_SUM_BP_SUB |
	    IPD_INT_SUM_PRC_PAR3 |
	    IPD_INT_SUM_PRC_PAR2 |
	    IPD_INT_SUM_PRC_PAR1 |
	    IPD_INT_SUM_PRC_PAR0);
	_IPD_WR8(sc, IPD_INT_SUM_OFFSET, ipd_int_xxx);
	_IPD_WR8(sc, IPD_INT_ENB_OFFSET, enable ? ipd_int_xxx : 0);
}

uint64_t
cn30xxipd_int_summary(struct cn30xxipd_softc *sc)
{
	uint64_t summary;

	summary = _IPD_RD8(sc, IPD_INT_SUM_OFFSET);
	_IPD_WR8(sc, IPD_INT_SUM_OFFSET, summary);
	return summary;
}

int
cn30xxipd_intr_drop(void *arg)
{
	octeon_xkphys_write_8(CIU_INT0_SUM0, CIU_INTX_SUM0_IPD_DRP);
	return (1);
}

#define	_ENTRY(x)	{ #x, x##_OFFSET }

struct cn30xxipd_dump_reg {
	const char *name;
	size_t	offset;
};

const struct cn30xxipd_dump_reg cn30xxipd_dump_regs[] = {
	_ENTRY(IPD_1ST_MBUFF_SKIP),
	_ENTRY(IPD_NOT_1ST_MBUFF_SKIP),
	_ENTRY(IPD_PACKET_MBUFF_SIZE),
	_ENTRY(IPD_CTL_STATUS),
	_ENTRY(IPD_WQE_FPA_QUEUE),
	_ENTRY(IPD_PORT0_BP_PAGE_CNT),
	_ENTRY(IPD_PORT1_BP_PAGE_CNT),
	_ENTRY(IPD_PORT2_BP_PAGE_CNT),
	_ENTRY(IPD_PORT32_BP_PAGE_CNT),
	_ENTRY(IPD_SUB_PORT_BP_PAGE_CNT),
	_ENTRY(IPD_1ST_NEXT_PTR_BACK),
	_ENTRY(IPD_2ND_NEXT_PTR_BACK),
	_ENTRY(IPD_INT_ENB),
	_ENTRY(IPD_INT_SUM),
	_ENTRY(IPD_SUB_PORT_FCS),
	_ENTRY(IPD_QOS0_RED_MARKS),
	_ENTRY(IPD_QOS1_RED_MARKS),
	_ENTRY(IPD_QOS2_RED_MARKS),
	_ENTRY(IPD_QOS3_RED_MARKS),
	_ENTRY(IPD_QOS4_RED_MARKS),
	_ENTRY(IPD_QOS5_RED_MARKS),
	_ENTRY(IPD_QOS6_RED_MARKS),
	_ENTRY(IPD_QOS7_RED_MARKS),
	_ENTRY(IPD_PORT_BP_COUNTERS_PAIR0),
	_ENTRY(IPD_PORT_BP_COUNTERS_PAIR1),
	_ENTRY(IPD_PORT_BP_COUNTERS_PAIR2),
	_ENTRY(IPD_PORT_BP_COUNTERS_PAIR32),
	_ENTRY(IPD_RED_PORT_ENABLE),
	_ENTRY(IPD_RED_QUE0_PARAM),
	_ENTRY(IPD_RED_QUE1_PARAM),
	_ENTRY(IPD_RED_QUE2_PARAM),
	_ENTRY(IPD_RED_QUE3_PARAM),
	_ENTRY(IPD_RED_QUE4_PARAM),
	_ENTRY(IPD_RED_QUE5_PARAM),
	_ENTRY(IPD_RED_QUE6_PARAM),
	_ENTRY(IPD_RED_QUE7_PARAM),
	_ENTRY(IPD_PTR_COUNT),
	_ENTRY(IPD_BP_PRT_RED_END),
	_ENTRY(IPD_QUE0_FREE_PAGE_CNT),
	_ENTRY(IPD_CLK_COUNT),
	_ENTRY(IPD_PWP_PTR_FIFO_CTL),
	_ENTRY(IPD_PRC_HOLD_PTR_FIFO_CTL),
	_ENTRY(IPD_PRC_PORT_PTR_FIFO_CTL),
	_ENTRY(IPD_PKT_PTR_VALID),
	_ENTRY(IPD_WQE_PTR_VALID),
	_ENTRY(IPD_BIST_STATUS),
};

void
cn30xxipd_dump(void)
{
	struct cn30xxipd_softc *sc;
	const struct cn30xxipd_dump_reg *reg;
	uint64_t tmp;
	int i;

	sc = __cn30xxipd_softc[0];
	for (i = 0; i < (int)nitems(cn30xxipd_dump_regs); i++) {
		reg = &cn30xxipd_dump_regs[i];
		tmp = _IPD_RD8(sc, reg->offset);
		printf("%-32s: %16llx\n", reg->name, tmp);
	}
}
#endif /* OCTEON_ETH_DEBUG */


code:
/*
 * THIS FILE IS AUTOMATICALLY GENERATED
 * DONT EDIT THIS FILE
 */

/*	$OpenBSD: cn30xxipdreg.h,v 1.2 2014/08/11 18:29:56 miod Exp $	*/

/*
 * 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.
 */

/*
 * Cavium Networks OCTEON CN30XX Hardware Reference Manual
 * CN30XX-HM-1.0
 * 7.9 IPD Registers
 */

#ifndef _CN30XXIPDREG_H_
#define _CN30XXIPDREG_H_

#define	IPD_1ST_MBUFF_SKIP		0x00014f0000000000ULL
#define	IPD_NOT_1ST_MBUFF_SKIP		0x00014f0000000008ULL
#define	IPD_PACKET_MBUFF_SIZE		0x00014f0000000010ULL
#define	IPD_CTL_STATUS			0x00014f0000000018ULL
#define	IPD_WQE_FPA_QUEUE		0x00014f0000000020ULL
#define	IPD_PORT0_BP_PAGE_CNT		0x00014f0000000028ULL
#define	IPD_PORT1_BP_PAGE_CNT		0x00014f0000000030ULL
#define	IPD_PORT2_BP_PAGE_CNT		0x00014f0000000038ULL
#define	IPD_PORT32_BP_PAGE_CNT		0x00014f0000000128ULL
#define	IPD_SUB_PORT_BP_PAGE_CNT	0x00014f0000000148ULL
#define	IPD_1ST_NEXT_PTR_BACK		0x00014f0000000150ULL
#define	IPD_2ND_NEXT_PTR_BACK		0x00014f0000000158ULL
#define	IPD_INT_ENB			0x00014f0000000160ULL
#define	IPD_INT_SUM			0x00014f0000000168ULL
#define	IPD_SUB_PORT_FCS		0x00014f0000000170ULL
#define	IPD_QOS0_RED_MARKS		0x00014f0000000178ULL
#define	IPD_QOS1_RED_MARKS		0x00014f0000000180ULL
#define	IPD_QOS2_RED_MARKS		0x00014f0000000188ULL
#define	IPD_QOS3_RED_MARKS		0x00014f0000000190ULL
#define	IPD_QOS4_RED_MARKS		0x00014f0000000198ULL
#define	IPD_QOS5_RED_MARKS		0x00014f00000001a0ULL
#define	IPD_QOS6_RED_MARKS		0x00014f00000001a8ULL
#define	IPD_QOS7_RED_MARKS		0x00014f00000001b0ULL
#define	IPD_PORT_BP_COUNTERS_PAIR0	0x00014f00000001b8ULL
#define	IPD_PORT_BP_COUNTERS_PAIR1	0x00014f00000001c0ULL
#define	IPD_PORT_BP_COUNTERS_PAIR2	0x00014f00000001c8ULL
#define	IPD_PORT_BP_COUNTERS_PAIR32	0x00014f00000002b8ULL
#define	IPD_RED_PORT_ENABLE		0x00014f00000002d8ULL
#define	IPD_RED_QUE0_PARAM		0x00014f00000002e0ULL
#define	IPD_RED_QUE1_PARAM		0x00014f00000002e8ULL
#define	IPD_RED_QUE2_PARAM		0x00014f00000002f0ULL
#define	IPD_RED_QUE3_PARAM		0x00014f00000002f8ULL
#define	IPD_RED_QUE4_PARAM		0x00014f0000000300ULL
#define	IPD_RED_QUE5_PARAM		0x00014f0000000308ULL
#define	IPD_RED_QUE6_PARAM		0x00014f0000000310ULL
#define	IPD_RED_QUE7_PARAM		0x00014f0000000318ULL
#define	IPD_PTR_COUNT			0x00014f0000000320ULL
#define	IPD_BP_PRT_RED_END		0x00014f0000000328ULL
#define	IPD_QUE0_FREE_PAGE_CNT		0x00014f0000000330ULL
#define	IPD_CLK_COUNT			0x00014f0000000338ULL
#define	IPD_PWP_PTR_FIFO_CTL		0x00014f0000000340ULL
#define	IPD_PRC_HOLD_PTR_FIFO_CTL	0x00014f0000000348ULL
#define	IPD_PRC_PORT_PTR_FIFO_CTL	0x00014f0000000350ULL
#define	IPD_PKT_PTR_VALID		0x00014f0000000358ULL
#define	IPD_WQE_PTR_VALID		0x00014f0000000360ULL
#define	IPD_BIST_STATUS			0x00014f00000007f8ULL

#define	IPD_BASE			0x00014f0000000000ULL
#define	IPD_SIZE			0x800ULL

#define	IPD_1ST_MBUFF_SKIP_OFFSET		0x0ULL
#define	IPD_NOT_1ST_MBUFF_SKIP_OFFSET		0x8ULL
#define	IPD_PACKET_MBUFF_SIZE_OFFSET		0x10ULL
#define	IPD_CTL_STATUS_OFFSET			0x18ULL
#define	IPD_WQE_FPA_QUEUE_OFFSET		0x20ULL
#define	IPD_PORT0_BP_PAGE_CNT_OFFSET		0x28ULL
#define	IPD_PORT1_BP_PAGE_CNT_OFFSET		0x30ULL
#define	IPD_PORT2_BP_PAGE_CNT_OFFSET		0x38ULL
#define	IPD_PORT32_BP_PAGE_CNT_OFFSET		0x128ULL
#define	IPD_SUB_PORT_BP_PAGE_CNT_OFFSET		0x148ULL
#define	IPD_1ST_NEXT_PTR_BACK_OFFSET		0x150ULL
#define	IPD_2ND_NEXT_PTR_BACK_OFFSET		0x158ULL
#define	IPD_INT_ENB_OFFSET			0x160ULL
#define	IPD_INT_SUM_OFFSET			0x168ULL
#define	IPD_SUB_PORT_FCS_OFFSET			0x170ULL
#define	IPD_QOS0_RED_MARKS_OFFSET		0x178ULL
#define	IPD_QOS1_RED_MARKS_OFFSET		0x180ULL
#define	IPD_QOS2_RED_MARKS_OFFSET		0x188ULL
#define	IPD_QOS3_RED_MARKS_OFFSET		0x190ULL
#define	IPD_QOS4_RED_MARKS_OFFSET		0x198ULL
#define	IPD_QOS5_RED_MARKS_OFFSET		0x1a0ULL
#define	IPD_QOS6_RED_MARKS_OFFSET		0x1a8ULL
#define	IPD_QOS7_RED_MARKS_OFFSET		0x1b0ULL
#define	IPD_PORT_BP_COUNTERS_PAIR0_OFFSET	0x1b8ULL
#define	IPD_PORT_BP_COUNTERS_PAIR1_OFFSET	0x1c0ULL
#define	IPD_PORT_BP_COUNTERS_PAIR2_OFFSET	0x1c8ULL
#define	IPD_PORT_BP_COUNTERS_PAIR32_OFFSET	0x2b8ULL
#define	IPD_RED_PORT_ENABLE_OFFSET		0x2d8ULL
#define	IPD_RED_QUE0_PARAM_OFFSET		0x2e0ULL
#define	IPD_RED_QUE1_PARAM_OFFSET		0x2e8ULL
#define	IPD_RED_QUE2_PARAM_OFFSET		0x2f0ULL
#define	IPD_RED_QUE3_PARAM_OFFSET		0x2f8ULL
#define	IPD_RED_QUE4_PARAM_OFFSET		0x300ULL
#define	IPD_RED_QUE5_PARAM_OFFSET		0x308ULL
#define	IPD_RED_QUE6_PARAM_OFFSET		0x310ULL
#define	IPD_RED_QUE7_PARAM_OFFSET		0x318ULL
#define	IPD_PTR_COUNT_OFFSET			0x320ULL
#define	IPD_BP_PRT_RED_END_OFFSET		0x328ULL
#define	IPD_QUE0_FREE_PAGE_CNT_OFFSET		0x330ULL
#define	IPD_CLK_COUNT_OFFSET			0x338ULL
#define	IPD_PWP_PTR_FIFO_CTL_OFFSET		0x340ULL
#define	IPD_PRC_HOLD_PTR_FIFO_CTL_OFFSET	0x348ULL
#define	IPD_PRC_PORT_PTR_FIFO_CTL_OFFSET	0x350ULL
#define	IPD_PKT_PTR_VALID_OFFSET		0x358ULL
#define	IPD_WQE_PTR_VALID_OFFSET		0x360ULL
#define	IPD_BIST_STATUS_OFFSET			0x7f8ULL

/* ----- */
/*
 * Work Queue Entry Format (for input packet)
 * 7.5 Work Queue Entry
 * Figure 7-8. PIP/IPD Hardware Work-Queue Entry
 */

/*
 * word 2
 * Figure. 7-9 Work-Queue Entry format; Word2 Cases
 */
/* RAWFULL */
#define IPD_WQE_WORD2_RAW_BUFS		0xff00000000000000ULL
#define IPD_WQE_WORD2_RAW_WORD		0x00ffffffffffffffULL

/* is IP */
#define IPD_WQE_WORD2_IP_BUFS		0xff00000000000000ULL
#define IPD_WQE_WORD2_IP_IPOFF		0x00ff000000000000ULL
#define IPD_WQE_WORD2_IP_VV		0x0000800000000000ULL
#define IPD_WQE_WORD2_IP_VS		0x0000400000000000ULL
#define IPD_WQE_WORD2_IP_45		0x0000200000000000ULL
#define IPD_WQE_WORD2_IP_VC		0x0000100000000000ULL
#define IPD_WQE_WORD2_IP_VLANID		0x00000fff00000000ULL
#define IPD_WQE_WORD2_IP_31_20		0x00000000fff00000ULL
#define IPD_WQE_WORD2_IP_CO		0x0000000000080000ULL
#define IPD_WQE_WORD2_IP_TU		0x0000000000040000ULL
#define IPD_WQE_WORD2_IP_SE		0x0000000000020000ULL
#define IPD_WQE_WORD2_IP_V6		0x0000000000010000ULL
#define IPD_WQE_WORD2_IP_15		0x0000000000008000ULL
#define IPD_WQE_WORD2_IP_LE		0x0000000000004000ULL
#define IPD_WQE_WORD2_IP_FR		0x0000000000002000ULL
#define IPD_WQE_WORD2_IP_IE		0x0000000000001000ULL
#define IPD_WQE_WORD2_IP_B		0x0000000000000800ULL
#define IPD_WQE_WORD2_IP_M		0x0000000000000400ULL
#define IPD_WQE_WORD2_IP_NI		0x0000000000000200ULL
#define IPD_WQE_WORD2_IP_RE		0x0000000000000100ULL
#define IPD_WQE_WORD2_IP_OPCODE		0x00000000000000ffULL

/* All other */
#define IPD_WQE_WORD2_OTH_BUFS		0xff00000000000000ULL
#define IPD_WQE_WORD2_OTH_55_48		0x00ff000000000000ULL
#define IPD_WQE_WORD2_OTH_VV		0x0000800000000000ULL
#define IPD_WQE_WORD2_OTH_VS		0x0000400000000000ULL
#define IPD_WQE_WORD2_OTH_45		0x0000200000000000ULL
#define IPD_WQE_WORD2_OTH_VC		0x0000100000000000ULL
#define IPD_WQE_WORD2_OTH_VLANID	0x00000fff00000000ULL
#define IPD_WQE_WORD2_OTH_31_14		0x00000000ffffc000ULL
#define IPD_WQE_WORD2_OTH_IR		0x0000000000002000ULL
#define IPD_WQE_WORD2_OTH_IA		0x0000000000001000ULL
#define IPD_WQE_WORD2_OTH_B		0x0000000000000800ULL
#define IPD_WQE_WORD2_OTH_M		0x0000000000000400ULL
#define IPD_WQE_WORD2_OTH_NI		0x0000000000000200ULL
#define IPD_WQE_WORD2_OTH_RE		0x0000000000000100ULL
#define IPD_WQE_WORD2_OTH_OPCODE	0x00000000000000ffULL

/*
 * word 3
 */
#define IPD_WQE_WORD3_63		0x8000000000000000ULL
#define IPD_WQE_WORD3_BACK		0x7800000000000000ULL
#define IPD_WQE_WORD3_58_56		0x0700000000000000ULL
#define IPD_WQE_WORD3_SIZE		0x00ffff0000000000ULL
#define IPD_WQE_WORD3_ADDR		0x000000ffffffffffULL

/*
 * IPD_1ST_MBUFF_SKIP
 */
#define IPD_1ST_MBUFF_SKIP_63_6		0xffffffffffffffc0ULL
#define IPD_1ST_MBUFF_SKIP_SZ		0x000000000000003fULL

/*
 * IPD_NOT_1ST_MBUFF_SKIP
 */
#define IPD_NOT_1ST_MBUFF_SKIP_63_6	0xffffffffffffffc0ULL
#define IPD_NOT_1ST_MBUFF_SKIP_SZ	0x000000000000003fULL

/*
 * IPD_PACKET_MBUFF_SIZE
 */
#define IPD_PACKET_MBUFF_SIZE_63_12	0xfffffffffffff000ULL
#define IPD_PACKET_MBUFF_SIZE_MB_SIZE	0x0000000000000fffULL

/*
 * IPD_CTL_STATUS
 */
#define IPD_CTL_STATUS_63_10		0xfffffffffffffc00ULL
#define IPD_CTL_STATUS_LEN_M8		0x0000000000000200ULL
#define IPD_CTL_STATUS_RESET		0x0000000000000100ULL
#define IPD_CTL_STATUS_ADDPKT		0x0000000000000080ULL
#define IPD_CTL_STATUS_NADDBUF		0x0000000000000040ULL
#define IPD_CTL_STATUS_PKT_LEND		0x0000000000000020ULL
#define IPD_CTL_STATUS_WQE_LEND		0x0000000000000010ULL
#define IPD_CTL_STATUS_PBP_EN		0x0000000000000008ULL
#define IPD_CTL_STATUS_OPC_MODE		0x0000000000000006ULL
#define  IPD_CTL_STATUS_OPC_MODE_SHIFT	1
#define   IPD_CTL_STATUS_OPC_MODE_NONE	(0ULL << IPD_CTL_STATUS_OPC_MODE_SHIFT)
#define   IPD_CTL_STATUS_OPC_MODE_ALL	(1ULL << IPD_CTL_STATUS_OPC_MODE_SHIFT)
#define   IPD_CTL_STATUS_OPC_MODE_ONE	(2ULL << IPD_CTL_STATUS_OPC_MODE_SHIFT)
#define   IPD_CTL_STATUS_OPC_MODE_TWO	(3ULL << IPD_CTL_STATUS_OPC_MODE_SHIFT)
#define IPD_CTL_STATUS_IPD_EN		0x0000000000000001ULL

/*
 * IPD_WQE_FPA_QUEUE
 */
#define IPD_WQE_FPA_QUEUE_63_3		0xfffffffffffffff8ULL
#define IPD_WQE_FPA_QUEUE_WQE_QUE	0x0000000000000007ULL

/*
 * IPD_PORTN_BP_PAGE_CNT
 */
#define IPD_PORTN_BP_PAGE_CNT_63_18	0xfffffffffffc0000ULL
#define IPD_PORTN_BP_PAGE_CNT_BP_ENB	0x0000000000020000ULL
#define IPD_PORTN_BP_PAGE_CNT_PAGE_CNT	0x000000000001ffffULL

/*
 * IPD_SUB_PORT_BP_PAGE_CNT
 */
#define IPD_SUB_PORT_BP_PAGE_CNT_63_18		0xffffffff80000000ULL
#define IPD_SUB_PORT_BP_PAGE_CNT_PORT		0x000000007e000000ULL
#define IPD_SUB_PORT_BP_PAGE_CNT_PAGE_CNT	0x0000000001ffffffULL

/*
 * IPD_1ST_NEXT_PTR_BACK
 */
#define IPD_1ST_NEXT_PTR_BACK_63_4		0xfffffffffffffff0ULL
#define IPD_1ST_NEXT_PTR_BACK_BACK		0x000000000000000fULL

/*
 * IPD_2ND_NEXT_PTR_BACK
 */
#define IPD_2ND_NEXT_PTR_BACK_63_4		0xfffffffffffffff0ULL
#define IPD_2ND_NEXT_PTR_BACK_BACK		0x000000000000000fULL

/*
 * IPD_INT_ENB
 */
#define IPD_INT_ENB_63_4		0xffffffffffffffe0ULL
#define IPD_INT_ENB_BP_SUB		0x0000000000000010ULL
#define IPD_INT_ENB_PRC_PAR3		0x0000000000000008ULL
#define IPD_INT_ENB_PRC_PAR2		0x0000000000000004ULL
#define IPD_INT_ENB_PRC_PAR1		0x0000000000000002ULL
#define IPD_INT_ENB_PRC_PAR0		0x0000000000000001ULL

/*
 * IPD_INT_SUM
 */
#define IPD_INT_SUM_63_4		0xffffffffffffffe0ULL
#define IPD_INT_SUM_BP_SUB		0x0000000000000010ULL
#define IPD_INT_SUM_PRC_PAR3		0x0000000000000008ULL
#define IPD_INT_SUM_PRC_PAR2		0x0000000000000004ULL
#define IPD_INT_SUM_PRC_PAR1		0x0000000000000002ULL
#define IPD_INT_SUM_PRC_PAR0		0x0000000000000001ULL

/*
 * IPD_SUB_PORT_FCS
 */
#define IPD_SUB_PORT_FCS_63_3		0xfffffffffffffff8ULL
#define IPD_SUB_PORT_FCS_PORT_BIT	0x0000000000000007ULL

/*
 * IPD_QOSN_RED_MARKS
 */
#define IPD_QOSN_READ_MARKS_DROP	0xffffffff00000000ULL
#define IPD_QOSN_READ_MARKS_PASS	0x00000000ffffffffULL

/*
 * IPD_PORT_BP_COUNTERS_PAIRN
 */
#define IPD_PORT_BP_COUNTERS_PAIRN_63_25	0xfffffffffe000000ULL
#define IPD_PORT_BP_COUNTERS_PAIRN_CNT_VAL	0x0000000001ffffffULL

/*
 * IPD_RED_PORT_ENABLE
 */
#define IPD_RED_PORT_ENABLE_PRB_DLY	0xfffc000000000000ULL
#define IPD_RED_PORT_ENABLE_AVG_DLY	0x0003fff000000000ULL
#define IPD_RED_PORT_ENABLE_PRT_ENB	0x0000000fffffffffULL

/*
 * IPD_RED_QUEN_PARAM
 */
#define IPD_RED_QUEN_PARAM_63_49	0xfffe000000000000ULL
#define IPD_RED_QUEN_PARAM_USE_PCNT	0x0001000000000000ULL
#define IPD_RED_QUEN_PARAM_NEW_CON	0x0000ff0000000000ULL
#define IPD_RED_QUEN_PARAM_AVG_CON	0x000000ff00000000ULL
#define IPD_RED_QUEN_PARAM_PRB_CON	0x00000000ffffffffULL

/*
 * IPD_PTR_COUNT
 */
#define IPD_PTR_COUNT_63_19		0xfffffffffff80000ULL
#define IPD_PTR_COUNT_PKTV_CNT		0x0000000000040000ULL
#define IPD_PTR_COUNT_WQEV_CNT		0x0000000000020000ULL
#define IPD_PTR_COUNT_PFIF_CNT		0x000000000001c000ULL
#define IPD_PTR_COUNT_PKT_PCNT		0x0000000000003f80ULL
#define IPD_PTR_COUNT_WQE_PCNT		0x000000000000007fULL

/*
 * IPD_BP_PRT_RED_END
 */
#define IPD_BP_PRT_RED_END_63_36	0xfffffff000000000ULL
#define IPD_BP_PRT_RED_END_PRT_ENB	0x0000000fffffffffULL

/*
 * IPD_QUE0_FREE_PAGE_CNT
 */
#define IPD_QUE0_FREE_PAGE_CNT_63_32	0xffffffff00000000ULL
#define IPD_QUE0_FREE_PAGE_CNT_Q0_PCNT	0x00000000ffffffffULL

/*
 * IPD_CLK_COUNT
 */
#define IPD_CLK_COUNT_CLK_CNT		0xffffffffffffffffULL

/*
 * IPD_PWP_PTR_FIFO_CTL
 */
#define IPD_PWP_PTR_FIFO_CTL_63_61	0xe000000000000000ULL
#define IPD_PWP_PTR_FIFO_CTL_MAX_CNTS	0x1fc0000000000000ULL
#define IPD_PWP_PTR_FIFO_CTL_WRADDR	0x003fc00000000000ULL
#define IPD_PWP_PTR_FIFO_CTL_PRADDR	0x00003fc000000000ULL
#define IPD_PWP_PTR_FIFO_CTL_PTR	0x0000003ffffffe00ULL
#define IPD_PWP_PTR_FIFO_CTL_CENA	0x0000000000000100ULL
#define IPD_PWP_PTR_FIFO_CTL_RADDR	0x00000000000000ffULL

/*
 * IPD_PRC_HOLD_PTR_FIFO_CTL
 */
#define IPD_PRC_HOLD_PTR_FIFO_CTL_63_39		0xffffff8000000000ULL
#define IPD_PRC_HOLD_PTR_FIFO_CTL_MAX_PTR	0x0000007000000000ULL
#define IPD_PRC_HOLD_PTR_FIFO_CTL_PRADDR	0x0000000e00000000ULL
#define IPD_PRC_HOLD_PTR_FIFO_CTL_PTR		0x00000001fffffff0ULL
#define IPD_PRC_HOLD_PTR_FIFO_CTL_CENA		0x0000000000000008ULL
#define IPD_PRC_HOLD_PTR_FIFO_CTL_RADDR		0x0000000000000007ULL

/*
 * IPD_PRC_PORT_PTR_FIFO_CTL
 */
#define IPD_PRC_PORT_PTR_FIFO_CTL_63_44		0xfffff00000000000ULL
#define IPD_PRC_PORT_PTR_FIFO_CTL_MAX_PTR	0x00000fe000000000ULL
#define IPD_PRC_PORT_PTR_FIFO_CTL_PTR		0x0000001fffffff00ULL
#define IPD_PRC_PORT_PTR_FIFO_CTL_CENA		0x0000000000000080ULL
#define IPD_PRC_PORT_PTR_FIFO_CTL_RADDR		0x000000000000007fULL

/*
 * IPD_PKT_PTR_VALID
 */
#define IPD_PKT_PTR_VALID_63_29	0xffffffffe0000000ULL
#define IPD_PKT_PTR_VALID_PTR	0x000000001fffffffULL

/*
 * IPD_WQE_PTR_VALID
 */
#define IPD_WQE_PTR_VALID_63_29	0xffffffffe0000000ULL
#define IPD_WQE_PTR_VALID_PTR	0x000000001fffffffULL

/*
 * IPD_BIST_STATUS
 */
#define IPD_BIST_STATUS_63_29		0xffffffffffff0000ULL
#define IPD_BIST_STATUS_PWQ_WQED	0x0000000000008000ULL
#define IPD_BIST_STATUS_PWQ_WP1		0x0000000000004000ULL
#define IPD_BIST_STATUS_PWQ_POW		0x0000000000002000ULL
#define IPD_BIST_STATUS_IPQ_PBE1	0x0000000000001000ULL
#define IPD_BIST_STATUS_IPQ_PBE0	0x0000000000000800ULL
#define IPD_BIST_STATUS_PBM3		0x0000000000000400ULL
#define IPD_BIST_STATUS_PBM2		0x0000000000000200ULL
#define IPD_BIST_STATUS_PBM1		0x0000000000000100ULL
#define IPD_BIST_STATUS_PBM0		0x0000000000000080ULL
#define IPD_BIST_STATUS_PBM_WORD	0x0000000000000040ULL
#define IPD_BIST_STATUS_PWQ1		0x0000000000000020ULL
#define IPD_BIST_STATUS_PWQ0		0x0000000000000010ULL
#define IPD_BIST_STATUS_PRC_OFF		0x0000000000000008ULL
#define IPD_BIST_STATUS_IPD_OLD		0x0000000000000004ULL
#define IPD_BIST_STATUS_IPD_NEW		0x0000000000000002ULL
#define IPD_BIST_STATUS_PWP		0x0000000000000001ULL

/*
 * word2[Opcode]
 */
/* L3 (IP) error */
#define IPD_WQE_L3_NOT_IP		1
#define IPD_WQE_L3_V4_CSUM_ERR		2
#define IPD_WQE_L3_HEADER_MALFORMED	3
#define IPD_WQE_L3_MELFORMED		4
#define IPD_WQE_L3_TTL_HOP		5
#define IPD_WQE_L3_IP_OPT		6

/* L4 (UDP/TCP) error */
#define IPD_WQE_L4_MALFORMED		1
#define IPD_WQE_L4_CSUM_ERR		2
#define IPD_WQE_L4_UDP_LEN_ERR		3
#define IPD_WQE_L4_BAD_PORT		4
#define IPD_WQE_L4_FIN_ONLY		8
#define IPD_WQE_L4_NO_FLAGS		9
#define IPD_WQE_L4_FIN_RST		10
#define IPD_WQE_L4_SYN_URG		11
#define IPD_WQE_L4_SYN_RST		12
#define IPD_WQE_L4_SYN_FIN		13

#endif /* _CN30XXIPDREG_H_ */


code:
/*	$OpenBSD: cn30xxipdvar.h,v 1.3 2014/08/11 18:29:56 miod Exp $	*/

/*
 * 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.
 */

#ifndef _CN30XXIPDVAR_H_
#define _CN30XXIPDVAR_H_

/* XXX */
struct cn30xxipd_softc {
	int			sc_port;
	bus_space_tag_t		sc_regt;
	bus_space_handle_t	sc_regh;
	size_t			sc_first_mbuff_skip;
	size_t			sc_not_first_mbuff_skip;
};

/* XXX */
struct cn30xxipd_attach_args {
	int			aa_port;
	bus_space_tag_t		aa_regt;
	size_t			aa_first_mbuff_skip;
	size_t			aa_not_first_mbuff_skip;
};

void			cn30xxipd_init(struct cn30xxipd_attach_args *,
			    struct cn30xxipd_softc **);
int			cn30xxipd_enable(struct cn30xxipd_softc *);
int			cn30xxipd_config(struct cn30xxipd_softc *);
void			cn30xxipd_sub_port_fcs(struct cn30xxipd_softc *, int);
void			cn30xxipd_offload(uint64_t, caddr_t, uint16_t *);

#ifdef OCTEON_ETH_DEBUG
void	cn30xxipd_int_enable(struct cn30xxipd_softc *, int);
uint64_t cn30xxipd_int_summary(struct cn30xxipd_softc *);
void	cn30xxipd_int_enable(struct cn30xxipd_softc *, int);
#endif /* OCTEON_ETH_DEBUG */

#endif