9front - general discussion about 9front
 help / color / mirror / Atom feed
From: Peter Kosyh <p.kosyh@gmail.com>
To: 9front@9front.org
Subject: [PATCH] alc ethernet driver port
Date: Mon, 05 Oct 2020 11:24:14 +0300	[thread overview]
Message-ID: <87lfgl13o1.fsf@factor-ts.ru> (raw)

[-- Attachment #1: Type: text/plain, Size: 309 bytes --]

Hello! In fact, i am not think that it should be merged in
upstream. Anyway, i have decided to send this patch. May be it will be
usefull for someone with eeepc or like this...

This is "fast & dirty" port of alc driver from openbsd. I have tested
this only on my eeepc 1000px few days and it seems to be ok.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: etheralc.patch --]
[-- Type: text/x-patch, Size: 95840 bytes --]

diff -r 484d3f8e5978 sys/src/9/pc/etheralc.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/9/pc/etheralc.c	Wed Sep 30 19:54:09 2020 +0300
@@ -0,0 +1,2087 @@
+/* this code is ported from openbsd if_alc.c */
+/* by Peter Kosyh */
+
+/* Original copyright message: */
+/*-
+ * Copyright (c) 2009, Pyun YongHyeon <yongari@FreeBSD.org>
+ * 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 unmodified, 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 AUTHOR 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 AUTHOR 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 "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/pci.h"
+#include "../port/error.h"
+#include "../port/netif.h"
+#include "../port/etherif.h"
+#include "../port/ethermii.h"
+#include "../pc/etheralc.h"
+
+#define DSCN	64 /* ring len, 256 is maximum */
+
+#define	letoh32(x)	(x)
+#define	htole32(x)      (x)
+#define	LO(x)		((uvlong) (x) & 0xFFFFFFFF)
+#define	HI(x)		((uvlong) (x) >> 32)
+
+enum {
+	attansic_l1e = (0x1026<<16)|0x1969,
+	attansic_l1 = (0x1048<<16)|0x1969,
+	attansic_l2c = (0x1062<<16)|0x1969,
+	attansic_l1c = (0x1063<<16)|0x1969,
+	attansic_l1d = (0x1073<<16)|0x1969,
+	attansic_l1d_1 = (0x1083<<16)|0x1969,
+	attansic_ar8162	= (0x1090<<16)|0x1969,
+	attansic_ar8161	= (0x1091<<16)|0x1969,
+	attansic_ar8172	= (0x10a0<<16)|0x1969,
+	attansic_ar8171	= (0x10a1<<16)|0x1969,
+	attansic_l2 = (0x2048<<16)|0x1969,
+	attansic_l2c_1 = (0x2060<<16)|0x1969,
+	attansic_l2c_2 = (0x2062<<16)|0x1969,
+	attansic_e2200 = (0xe091<<16)|0x1969,
+	attansic_e2400 = (0xe0a1<<16)|0x1969,
+	attansic_e2500 = (0xe0b1<<16)|0x1969,
+};
+
+enum {
+	alcfl_e2x00 = 1,
+	alcfl_link_war = 0x2,
+	alcfl_ar816x = 0x4,
+	alcfl_fasteth = 0x8,
+	alcfl_aps = 0x10,
+	alcfl_jumbo = 0x20,
+	alcfl_msi = 0x40,
+	alcfl_link = 0x80,
+	alcfl_pcie = 0x100,
+	alcfl_l0s = 0x200,
+	alcfl_l1s = 0x400,
+};
+
+/* Tx descriptor */
+typedef struct tx_desc {
+	uint len;
+	uint flags;
+	uvlong addr;
+} TxDesc;
+
+/* Rx free descriptor */
+typedef struct rx_desc {
+	uvlong addr;
+} RxDesc;
+
+/* Rx return descriptor */
+typedef struct rx_rdesc {
+	uint rdinfo;
+	uint rss;
+	uint vtag;
+	uint status;
+} RxRdesc;
+
+typedef struct Ctlr Ctlr;
+typedef struct Ctlr {
+	Ether *edev;
+	uvlong	port;
+	Pcidev *pcidev;
+	QLock	alock;			/* attach */
+	QLock	slock;
+	Lock	imlock;
+	Lock	tlock;
+	Ctlr   *next;
+	int	*mem;
+	uint	did;
+	uchar   rid;
+	uchar	phy;
+	int	excap;
+	int	active;
+	int	flags;
+	int	rcb;
+	int	dma_wr_burst;
+	int	dma_rd_burst;
+	Block	**tb;
+	Block	**rb;
+	int	rdfree;
+	int	tdfree;
+	int	rdh;
+	int	rdt;
+	int	tdh;
+	int	tdt;
+	TxDesc	*tx_ring;
+	RxDesc	*rx_ring;
+	RxRdesc *rrx_ring;
+	Mii	*mii;
+	int	lim;
+	int	rim;
+	Rendez	rrendez;
+	Rendez	lrendez;
+	uchar	ra[Eaddrlen];		/* receive address */
+} Ctlr;
+
+static Ctlr* alcctlrhead;
+static Ctlr* alcctlrtail;
+
+static uint
+csr32r(Ctlr *c, int r)
+{
+	uint v;
+	v = *(c->mem+(r/4));
+	return v;
+}
+static void
+csr32w(Ctlr *c, int r, uint v)
+{
+	*(c->mem+(r/4)) = v;
+}
+
+static uint
+csr16r(Ctlr *c, int r)
+{
+	uint v;
+	v = *(ushort*)(c->mem+(r/4));
+	return v;
+}
+
+static void
+csr16w(Ctlr *c, int r, ushort v)
+{
+	*((ushort *)(c->mem+(r/4))) = v;
+}
+
+static void
+mii_write_816x(Ctlr *ctlr, int phy, int reg, int val)
+{
+	uint clk, v;
+	int i;
+
+	if ((ctlr->flags & alcfl_link) != 0)
+		clk = MDIO_CLK_25_128;
+	else
+		clk = MDIO_CLK_25_4;
+	csr32w(ctlr, ALC_MDIO, MDIO_OP_EXECUTE | MDIO_OP_WRITE |
+	    ((val & MDIO_DATA_MASK) << MDIO_DATA_SHIFT) | MDIO_REG_ADDR(reg) |
+	    MDIO_SUP_PREAMBLE | clk);
+	for (i = ALC_PHY_TIMEOUT; i > 0; i--) {
+		microdelay(5);
+		v = csr32r(ctlr, ALC_MDIO);
+		if ((v & MDIO_OP_BUSY) == 0)
+			break;
+	}
+	if (i == 0)
+		print("%s: phy write timeout: phy %d, reg %d\n", ctlr->edev->name, phy, reg);
+}
+
+static void
+mii_write_813x(Ctlr *ctlr, int phy, int reg, int val)
+{
+	uint v;
+	int i;
+
+	csr32w(ctlr, ALC_MDIO, MDIO_OP_EXECUTE | MDIO_OP_WRITE |
+	    (val & MDIO_DATA_MASK) << MDIO_DATA_SHIFT |
+	    MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg));
+	for (i = ALC_PHY_TIMEOUT; i > 0; i--) {
+		microdelay(5);
+		v = csr32r(ctlr, ALC_MDIO);
+		if ((v & (MDIO_OP_EXECUTE | MDIO_OP_BUSY)) == 0)
+			break;
+	}
+	if (i == 0)
+		print("%s: phy write timeout: phy %d, reg %d\n", ctlr->edev->name, phy, reg);
+}
+
+static void
+mii_write(Ctlr *ctlr, int phy, int reg, int val)
+{
+	if (phy != ctlr->phy)
+		return;
+
+	if ((ctlr->flags & alcfl_ar816x) != 0)
+		mii_write_816x(ctlr, phy, reg, val);
+	else
+		mii_write_813x(ctlr, phy, reg, val);
+}
+
+static int
+mii_read_813x(Ctlr *ctlr, int phy, int reg)
+{
+	uint v = 0;
+	int i;
+
+	/*
+	 * For AR8132 fast ethernet controller, do not report 1000baseT
+	 * capability to mii(4). Even though AR8132 uses the same
+	 * model/revision number of F1 gigabit PHY, the PHY has no
+	 * ability to establish 1000baseT link.
+	 */
+	if ((ctlr->flags & alcfl_fasteth) != 0 &&
+	    reg == Esr)
+		return (0);
+
+	csr32w(ctlr, ALC_MDIO, MDIO_OP_EXECUTE | MDIO_OP_READ |
+	    MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg));
+	for (i = ALC_PHY_TIMEOUT; i > 0; i--) {
+		microdelay(5);
+		v = csr32r(ctlr, ALC_MDIO);
+		if ((v & (MDIO_OP_EXECUTE | MDIO_OP_BUSY)) == 0)
+			break;
+	}
+	if (i == 0) {
+		print("%s: phy read timeout: phy %d, reg %d\n", ctlr->edev->name, phy, reg);
+		return 0;
+	}
+
+	return ((v & MDIO_DATA_MASK) >> MDIO_DATA_SHIFT);
+}
+
+static int
+mii_read_816x(Ctlr *ctlr, int phy, int reg)
+{
+	uint clk, v = 0;
+	int i;
+	if ((ctlr->flags & alcfl_link) != 0)
+		clk = MDIO_CLK_25_128;
+	else
+		clk = MDIO_CLK_25_4;
+	csr32w(ctlr, ALC_MDIO, MDIO_OP_EXECUTE | MDIO_OP_READ |
+		MDIO_SUP_PREAMBLE | clk | MDIO_REG_ADDR(reg));
+	for (i = ALC_PHY_TIMEOUT; i > 0; i--) {
+		microdelay(5);
+		v = csr32r(ctlr, ALC_MDIO);
+		if ((v & MDIO_OP_BUSY) == 0)
+			break;
+	}
+
+	if (i == 0) {
+		print("%s: phy read timeout: phy %d, reg %d\n", ctlr->edev->name, phy, reg);
+		return (0);
+	}
+	return ((v & MDIO_DATA_MASK) >> MDIO_DATA_SHIFT);
+}
+
+static int
+mii_read(Ctlr *ctlr, int phy, int reg)
+{
+	uint v;
+
+	if (phy != ctlr->phy)
+		return 0;
+
+	if ((ctlr->flags & alcfl_ar816x) != 0)
+		v = mii_read_816x(ctlr, phy, reg);
+	else
+		v = mii_read_813x(ctlr, phy, reg);
+	return v;
+}
+static int
+phy_mii_read(Mii* mii, int pa, int ra)
+{
+	return mii_read(mii->ctlr, pa, ra);
+}
+
+static int
+phy_mii_write(Mii* mii, int pa, int ra, int data)
+{
+	mii_write(mii->ctlr, pa, ra, data);
+	return 0;
+}
+
+static int
+miidbg_read(Ctlr *ctlr, int reg)
+{
+	mii_write(ctlr, ctlr->phy, ALC_MII_DBG_ADDR, reg);
+	return mii_read(ctlr, ctlr->phy, ALC_MII_DBG_DATA);
+}
+
+static void
+miidbg_write(Ctlr *ctlr, int reg, int val)
+{
+	mii_write(ctlr, ctlr->phy, ALC_MII_DBG_ADDR,
+	    reg);
+	mii_write(ctlr, ctlr->phy, ALC_MII_DBG_DATA,
+	    val);
+}
+
+static int
+miiext_read(Ctlr *ctlr, int devaddr, int reg)
+{
+	uint clk, v = 0;
+	int i;
+
+	csr32w(ctlr, ALC_EXT_MDIO, EXT_MDIO_REG(reg) |
+	    EXT_MDIO_DEVADDR(devaddr));
+	if ((ctlr->flags & alcfl_link) != 0)
+		clk = MDIO_CLK_25_128;
+	else
+		clk = MDIO_CLK_25_4;
+	csr32w(ctlr, ALC_MDIO, MDIO_OP_EXECUTE | MDIO_OP_READ |
+	    MDIO_SUP_PREAMBLE | clk | MDIO_MODE_EXT);
+	for (i = ALC_PHY_TIMEOUT; i > 0; i--) {
+		microdelay(5);
+		v = csr32r(ctlr, ALC_MDIO);
+		if ((v & MDIO_OP_BUSY) == 0)
+			break;
+	}
+
+	if (i == 0) {
+		print("%s: phy ext read timeout: phy %d, reg %d\n",
+		    ctlr->edev->name, devaddr, reg);
+		return 0;
+	}
+	return ((v & MDIO_DATA_MASK) >> MDIO_DATA_SHIFT);
+}
+
+static void
+miiext_write(Ctlr *ctlr, int devaddr, int reg, int val)
+{
+	uint clk, v;
+	int i;
+
+	csr32w(ctlr, ALC_EXT_MDIO, EXT_MDIO_REG(reg) |
+	    EXT_MDIO_DEVADDR(devaddr));
+	if ((ctlr->flags & alcfl_link) != 0)
+		clk = MDIO_CLK_25_128;
+	else
+		clk = MDIO_CLK_25_4;
+	csr32w(ctlr, ALC_MDIO, MDIO_OP_EXECUTE | MDIO_OP_WRITE |
+	    ((val & MDIO_DATA_MASK) << MDIO_DATA_SHIFT) |
+	    MDIO_SUP_PREAMBLE | clk | MDIO_MODE_EXT);
+	for (i = ALC_PHY_TIMEOUT; i > 0; i--) {
+		microdelay(5);
+		v = csr32r(ctlr, ALC_MDIO);
+		if ((v & MDIO_OP_BUSY) == 0)
+			break;
+	}
+	if (i == 0)
+		print("%s: phy ext write timeout: phy %d, reg %d\n", ctlr->edev->name, devaddr, reg);
+}
+
+
+static void
+phy_reset_816x(Ctlr *ctlr)
+{
+	uint val;
+
+	val = csr32r(ctlr, ALC_GPHY_CFG);
+	val &= ~(GPHY_CFG_EXT_RESET | GPHY_CFG_LED_MODE |
+	    GPHY_CFG_GATE_25M_ENB | GPHY_CFG_PHY_IDDQ | GPHY_CFG_PHY_PLL_ON |
+	    GPHY_CFG_PWDOWN_HW | GPHY_CFG_100AB_ENB);
+	val |= GPHY_CFG_SEL_ANA_RESET;
+	/* Disable PHY hibernation. */
+	val &= ~(GPHY_CFG_HIB_PULSE | GPHY_CFG_HIB_EN);
+	csr32w(ctlr, ALC_GPHY_CFG, val);
+	microdelay(10);
+	csr32w(ctlr, ALC_GPHY_CFG, val | GPHY_CFG_EXT_RESET);
+	microdelay(800);
+	/* Vendor PHY magic. */
+	/* Disable PHY hibernation. */
+	miidbg_write(ctlr, MII_DBG_LEGCYPS,
+	    DBG_LEGCYPS_DEFAULT & ~DBG_LEGCYPS_ENB);
+	miidbg_write(ctlr, MII_DBG_HIBNEG, DBG_HIBNEG_DEFAULT &
+	    ~(DBG_HIBNEG_PSHIB_EN | DBG_HIBNEG_HIB_PULSE));
+	miidbg_write(ctlr, MII_DBG_GREENCFG, DBG_GREENCFG_DEFAULT);
+	/* XXX Disable EEE. */
+	val = csr32r(ctlr, ALC_LPI_CTL);
+	val &= ~LPI_CTL_ENB;
+	csr32w(ctlr, ALC_LPI_CTL, val);
+	miiext_write(ctlr, MII_EXT_ANEG, MII_EXT_ANEG_LOCAL_EEEADV, 0);
+	/* PHY power saving. */
+	miidbg_write(ctlr, MII_DBG_TST10BTCFG, DBG_TST10BTCFG_DEFAULT);
+	miidbg_write(ctlr, MII_DBG_SRDSYSMOD, DBG_SRDSYSMOD_DEFAULT);
+	miidbg_write(ctlr, MII_DBG_TST100BTCFG, DBG_TST100BTCFG_DEFAULT);
+	miidbg_write(ctlr, MII_DBG_ANACTL, DBG_ANACTL_DEFAULT);
+	val = miidbg_read(ctlr, MII_DBG_GREENCFG2);
+	val &= ~DBG_GREENCFG2_GATE_DFSE_EN;
+	miidbg_write(ctlr, MII_DBG_GREENCFG2, val);
+	/* RTL8139C, 120m issue. */
+	miiext_write(ctlr, MII_EXT_ANEG, MII_EXT_ANEG_NLP78,
+	    ANEG_NLP78_120M_DEFAULT);
+	miiext_write(ctlr, MII_EXT_ANEG, MII_EXT_ANEG_S3DIG10,
+	    ANEG_S3DIG10_DEFAULT);
+	if ((ctlr->flags & alcfl_link_war) != 0) {
+		/* Turn off half amplitude. */
+		val = miiext_read(ctlr, MII_EXT_PCS, MII_EXT_CLDCTL3);
+		val |= EXT_CLDCTL3_BP_CABLE1TH_DET_GT;
+		miiext_write(ctlr, MII_EXT_PCS, MII_EXT_CLDCTL3, val);
+		/* Turn off Green feature. */
+		val = miidbg_read(ctlr, MII_DBG_GREENCFG2);
+		val |= DBG_GREENCFG2_BP_GREEN;
+		miidbg_write(ctlr, MII_DBG_GREENCFG2, val);
+		/* Turn off half bias. */
+		val = miiext_read(ctlr, MII_EXT_PCS, MII_EXT_CLDCTL5);
+		val |= EXT_CLDCTL5_BP_VD_HLFBIAS;
+		miiext_write(ctlr, MII_EXT_PCS, MII_EXT_CLDCTL5, val);
+	}
+}
+
+static void
+phy_reset_813x(Ctlr *ctlr)
+{
+	uint data;
+
+	/* Reset magic from Linux. */
+	csr16w(ctlr, ALC_GPHY_CFG, GPHY_CFG_SEL_ANA_RESET);
+	csr16r(ctlr, ALC_GPHY_CFG);
+	microdelay(10 * 1000);
+
+	csr16w(ctlr, ALC_GPHY_CFG, GPHY_CFG_EXT_RESET |
+	    GPHY_CFG_SEL_ANA_RESET);
+	csr16r(ctlr, ALC_GPHY_CFG);
+	microdelay(10 * 1000);
+
+	/* DSP fixup, Vendor magic. */
+	if (ctlr->did == attansic_l2c_1) {
+		mii_write(ctlr, ctlr->phy, ALC_MII_DBG_ADDR, 0x000A);
+		data = mii_read(ctlr, ctlr->phy, ALC_MII_DBG_DATA);
+		mii_write(ctlr, ctlr->phy, ALC_MII_DBG_DATA, data & 0xDFFF);
+	}
+	if (ctlr->did == attansic_l1d ||
+	    ctlr->did == attansic_l1d_1 ||
+	    ctlr->did == attansic_l2c_1 ||
+	    ctlr->did == attansic_l2c_2) {
+		mii_write(ctlr, ctlr->phy, ALC_MII_DBG_ADDR, 0x003B);
+		data = mii_read(ctlr, ctlr->phy, ALC_MII_DBG_DATA);
+		mii_write(ctlr, ctlr->phy, ALC_MII_DBG_DATA, data & 0xFFF7);
+		microdelay(20 * 1000);
+	}
+	if (ctlr->did == attansic_l1d) {
+		mii_write(ctlr, ctlr->phy, ALC_MII_DBG_ADDR, 0x0029);
+		mii_write(ctlr, ctlr->phy, ALC_MII_DBG_DATA, 0x929D);
+	}
+	if (ctlr->did == attansic_l1c ||
+	    ctlr->did == attansic_l2c ||
+	    ctlr->did == attansic_l1d_1 ||
+	    ctlr->did == attansic_l2c_2) {
+		mii_write(ctlr, ctlr->phy, ALC_MII_DBG_ADDR, 0x0029);
+		mii_write(ctlr, ctlr->phy, ALC_MII_DBG_DATA, 0xB6DD);
+	}
+
+	/* Load DSP codes, vendor magic. */
+	data = ANA_LOOP_SEL_10BT | ANA_EN_MASK_TB | ANA_EN_10BT_IDLE |
+	    ((1 << ANA_INTERVAL_SEL_TIMER_SHIFT) & ANA_INTERVAL_SEL_TIMER_MASK);
+	mii_write(ctlr, ctlr->phy, ALC_MII_DBG_ADDR, MII_ANA_CFG18);
+	mii_write(ctlr, ctlr->phy, ALC_MII_DBG_DATA, data);
+
+	data = ((2 << ANA_SERDES_CDR_BW_SHIFT) & ANA_SERDES_CDR_BW_MASK) |
+	    ANA_SERDES_EN_DEEM | ANA_SERDES_SEL_HSP | ANA_SERDES_EN_PLL |
+	    ANA_SERDES_EN_LCKDT;
+	mii_write(ctlr, ctlr->phy, ALC_MII_DBG_ADDR, MII_ANA_CFG5);
+	mii_write(ctlr, ctlr->phy, ALC_MII_DBG_DATA, data);
+
+	data = ((44 << ANA_LONG_CABLE_TH_100_SHIFT) &
+	    ANA_LONG_CABLE_TH_100_MASK) |
+	    ((33 << ANA_SHORT_CABLE_TH_100_SHIFT) &
+	    ANA_SHORT_CABLE_TH_100_SHIFT) |
+	    ANA_BP_BAD_LINK_ACCUM | ANA_BP_SMALL_BW;
+	mii_write(ctlr, ctlr->phy, ALC_MII_DBG_ADDR, MII_ANA_CFG54);
+	mii_write(ctlr, ctlr->phy, ALC_MII_DBG_DATA, data);
+
+	data = ((11 << ANA_IECHO_ADJ_3_SHIFT) & ANA_IECHO_ADJ_3_MASK) |
+	    ((11 << ANA_IECHO_ADJ_2_SHIFT) & ANA_IECHO_ADJ_2_MASK) |
+	    ((8 << ANA_IECHO_ADJ_1_SHIFT) & ANA_IECHO_ADJ_1_MASK) |
+	    ((8 << ANA_IECHO_ADJ_0_SHIFT) & ANA_IECHO_ADJ_0_MASK);
+	mii_write(ctlr, ctlr->phy, ALC_MII_DBG_ADDR, MII_ANA_CFG4);
+	mii_write(ctlr, ctlr->phy, ALC_MII_DBG_DATA, data);
+
+	data = ((7 & ANA_MANUL_SWICH_ON_SHIFT) & ANA_MANUL_SWICH_ON_MASK) |
+	    ANA_RESTART_CAL | ANA_MAN_ENABLE | ANA_SEL_HSP | ANA_EN_HB |
+	    ANA_OEN_125M;
+	mii_write(ctlr, ctlr->phy, ALC_MII_DBG_ADDR, MII_ANA_CFG0);
+	mii_write(ctlr, ctlr->phy, ALC_MII_DBG_DATA, data);
+	microdelay(1000);
+
+	/* Disable hibernation. */
+	mii_write(ctlr, ctlr->phy, ALC_MII_DBG_ADDR, 0x0029);
+	data = mii_read(ctlr, ctlr->phy, ALC_MII_DBG_DATA);
+	data &= ~0x8000;
+	mii_write(ctlr, ctlr->phy, ALC_MII_DBG_DATA, data);
+
+	mii_write(ctlr, ctlr->phy, ALC_MII_DBG_ADDR, 0x000B);
+	data = mii_read(ctlr, ctlr->phy, ALC_MII_DBG_DATA);
+	data &= ~0x8000;
+	mii_write(ctlr, ctlr->phy, ALC_MII_DBG_DATA, data);
+}
+
+static void
+phy_reset(Ctlr *ctlr)
+{
+	if (ctlr->flags & alcfl_ar816x)
+		phy_reset_816x(ctlr);
+	else
+		phy_reset_813x(ctlr);
+	mii_write(ctlr, ctlr->phy, 0x12, 0xc00); /* enable phy interrupts */
+}
+
+static void
+get_mac_par(Ctlr *ctlr)
+{
+	uint ea[2];
+
+	ea[0] = csr32r(ctlr, ALC_PAR0);
+	ea[1] = csr32r(ctlr, ALC_PAR1);
+	ctlr->ra[0] = (ea[1] >> 8) & 0xFF;
+	ctlr->ra[1] = (ea[1] >> 0) & 0xFF;
+	ctlr->ra[2] = (ea[0] >> 24) & 0xFF;
+	ctlr->ra[3] = (ea[0] >> 16) & 0xFF;
+	ctlr->ra[4] = (ea[0] >> 8) & 0xFF;
+	ctlr->ra[5] = (ea[0] >> 0) & 0xFF;
+}
+
+
+static void
+get_mac_816x(Ctlr *ctlr)
+{
+	uint reg = 0;
+	int i, reloaded;
+
+	reloaded = 0;
+	/* Try to reload station address via TWSI. */
+	for (i = 100; i > 0; i--) {
+		reg = csr32r(ctlr, ALC_SLD);
+		if ((reg & (SLD_PROGRESS | SLD_START)) == 0)
+			break;
+		microdelay(1000);
+	}
+	if (i != 0) {
+		csr32w(ctlr, ALC_SLD, reg | SLD_START);
+		for (i = 100; i > 0; i--) {
+			microdelay(1000);
+			reg = csr32r(ctlr, ALC_SLD);
+			if ((reg & SLD_START) == 0)
+				break;
+		}
+		if (i != 0)
+			reloaded++;
+		else
+			print("%s: reloading station address via TWSI timed"
+			    "out!\n", ctlr->edev->name);
+	}
+
+	/* Try to reload station address from EEPROM or FLASH. */
+	if (reloaded == 0) {
+		reg = csr32r(ctlr, ALC_EEPROM_LD);
+		if ((reg & (EEPROM_LD_EEPROM_EXIST |
+		    EEPROM_LD_FLASH_EXIST)) != 0) {
+			for (i = 100; i > 0; i--) {
+				reg = csr32r(ctlr, ALC_EEPROM_LD);
+				if ((reg & (EEPROM_LD_PROGRESS |
+				    EEPROM_LD_START)) == 0)
+					break;
+				microdelay(1000);
+			}
+			if (i != 0) {
+				csr32w(ctlr, ALC_EEPROM_LD, reg |
+				    EEPROM_LD_START);
+				for (i = 100; i > 0; i--) {
+					microdelay(1000);
+					reg = csr32r(ctlr, ALC_EEPROM_LD);
+					if ((reg & EEPROM_LD_START) == 0)
+						break;
+				}
+			} else
+				print("%s: reloading EEPROM/FLASH timed out!\n",
+				    ctlr->edev->name);
+		}
+	}
+	get_mac_par(ctlr);
+}
+
+static void
+get_mac_813x(Ctlr *ctlr)
+{
+	uint opt;
+	ushort val;
+	int eeprom, i;
+
+	eeprom = 0;
+	opt = csr32r(ctlr, ALC_OPT_CFG);
+	if ((csr32r(ctlr, ALC_MASTER_CFG) & MASTER_OTP_SEL) != 0 &&
+	    (csr32r(ctlr, ALC_TWSI_DEBUG) & TWSI_DEBUG_DEV_EXIST) != 0) {
+		/*
+		 * EEPROM found, let TWSI reload EEPROM configuration.
+		 * This will set ethernet address of controller.
+		 */
+		eeprom++;
+		switch (ctlr->did) {
+		case attansic_l1c:
+		case attansic_l2c:
+			if ((opt & OPT_CFG_CLK_ENB) == 0) {
+				opt |= OPT_CFG_CLK_ENB;
+				csr32w(ctlr, ALC_OPT_CFG, opt);
+				csr32r(ctlr, ALC_OPT_CFG);
+				microdelay(1000);
+			}
+			break;
+		case attansic_l1d:
+		case attansic_l1d_1:
+		case attansic_l2c_1:
+		case attansic_l2c_2:
+			mii_write(ctlr, ctlr->phy, ALC_MII_DBG_ADDR, 0x00);
+			val = mii_read(ctlr, ctlr->phy, ALC_MII_DBG_DATA);
+			mii_write(ctlr, ctlr->phy, ALC_MII_DBG_DATA, val & 0xFF7F);
+			mii_write(ctlr, ctlr->phy, ALC_MII_DBG_ADDR, 0x3B);
+			val = mii_read(ctlr, ctlr->phy, ALC_MII_DBG_DATA);
+			mii_write(ctlr, ctlr->phy, ALC_MII_DBG_DATA, val | 0x0008);
+			microdelay(20);
+			break;
+		}
+
+		csr32w(ctlr, ALC_LTSSM_ID_CFG,
+		    csr32r(ctlr, ALC_LTSSM_ID_CFG) & ~LTSSM_ID_WRO_ENB);
+		csr32w(ctlr, ALC_WOL_CFG, 0);
+		csr32r(ctlr, ALC_WOL_CFG);
+
+		csr32w(ctlr, ALC_TWSI_CFG, csr32r(ctlr, ALC_TWSI_CFG) |
+		    TWSI_CFG_SW_LD_START);
+		for (i = 100; i > 0; i--) {
+			microdelay(1000);
+			if ((csr32r(ctlr, ALC_TWSI_CFG) &
+			    TWSI_CFG_SW_LD_START) == 0)
+				break;
+		}
+		if (i == 0)
+			print("%s: reloading EEPROM timeout!\n",
+			    ctlr->edev->name);
+	} else {
+		print("%s: EEPROM not found!\n", ctlr->edev->name);
+	}
+	if (eeprom != 0) {
+		switch (ctlr->did) {
+		case attansic_l1c:
+		case attansic_l2c:
+			if ((opt & OPT_CFG_CLK_ENB) != 0) {
+				opt &= ~OPT_CFG_CLK_ENB;
+				csr32w(ctlr, ALC_OPT_CFG, opt);
+				csr32r(ctlr, ALC_OPT_CFG);
+				microdelay(1000);
+			}
+			break;
+		case attansic_l1d:
+		case attansic_l1d_1:
+		case attansic_l2c_1:
+		case attansic_l2c_2:
+			mii_write(ctlr, ctlr->phy, ALC_MII_DBG_ADDR, 0x00);
+			val = mii_read(ctlr, ctlr->phy, ALC_MII_DBG_DATA);
+			mii_write(ctlr, ctlr->phy, ALC_MII_DBG_DATA, val | 0x0080);
+			mii_write(ctlr, ctlr->phy, ALC_MII_DBG_ADDR, 0x3B);
+			val = mii_read(ctlr, ctlr->phy, ALC_MII_DBG_DATA);
+			mii_write(ctlr, ctlr->phy, ALC_MII_DBG_DATA, val & 0xFFF7);
+			microdelay(20);
+			break;
+		}
+	}
+	get_mac_par(ctlr);
+}
+
+static void
+get_mac(Ctlr *ctlr)
+{
+	if (ctlr->flags & alcfl_ar816x)
+		get_mac_816x(ctlr);
+	else
+		get_mac_813x(ctlr);
+}
+
+static void
+queue_start(Ctlr *ctlr)
+{
+	uint qcfg[] = {
+		0,
+		RXQ_CFG_QUEUE0_ENB,
+		RXQ_CFG_QUEUE0_ENB | RXQ_CFG_QUEUE1_ENB,
+		RXQ_CFG_QUEUE0_ENB | RXQ_CFG_QUEUE1_ENB | RXQ_CFG_QUEUE2_ENB,
+		RXQ_CFG_ENB
+	};
+	uint cfg;
+
+	/* Enable RxQ. */
+	cfg = csr32r(ctlr, ALC_RXQ_CFG);
+	if ((ctlr->flags & alcfl_ar816x) == 0) {
+		cfg &= ~RXQ_CFG_ENB;
+		cfg |= qcfg[1];
+	} else
+		cfg |= RXQ_CFG_QUEUE0_ENB;
+
+	csr32w(ctlr, ALC_RXQ_CFG, cfg);
+	/* Enable TxQ. */
+	cfg = csr32r(ctlr, ALC_TXQ_CFG);
+	cfg |= TXQ_CFG_ENB;
+	csr32w(ctlr, ALC_TXQ_CFG, cfg);
+}
+
+static void
+queue_stop(Ctlr *ctlr)
+{
+	uint reg;
+	int i;
+
+	/* Disable RxQ. */
+	reg = csr32r(ctlr, ALC_RXQ_CFG);
+	if ((ctlr->flags & alcfl_ar816x) == 0) {
+		if ((reg & RXQ_CFG_ENB) != 0) {
+			reg &= ~RXQ_CFG_ENB;
+			csr32w(ctlr, ALC_RXQ_CFG, reg);
+		}
+	} else {
+		if ((reg & RXQ_CFG_QUEUE0_ENB) != 0) {
+			reg &= ~RXQ_CFG_QUEUE0_ENB;
+			csr32w(ctlr, ALC_RXQ_CFG, reg);
+		}
+	}
+	/* Disable TxQ. */
+	reg = csr32r(ctlr, ALC_TXQ_CFG);
+	if ((reg & TXQ_CFG_ENB) != 0) {
+		reg &= ~TXQ_CFG_ENB;
+		csr32w(ctlr, ALC_TXQ_CFG, reg);
+	}
+	microdelay(40);
+	for (i = ALC_TIMEOUT; i > 0; i--) {
+		reg = csr32r(ctlr, ALC_IDLE_STATUS);
+		if ((reg & (IDLE_STATUS_RXQ | IDLE_STATUS_TXQ)) == 0)
+			break;
+		microdelay(10);
+	}
+	if (i == 0)
+		print("%s: could not disable RxQ/TxQ (0x%08x)!\n", ctlr->edev->name, reg);
+}
+
+static void
+mac_config(Ctlr *ctlr)
+{
+	uint reg;
+	MiiPhy *phy;
+	phy = ctlr->mii->curphy;
+	if (phy == nil)
+		return;
+	reg = csr32r(ctlr, ALC_MAC_CFG);
+	reg &= ~(MAC_CFG_FULL_DUPLEX | MAC_CFG_TX_FC | MAC_CFG_RX_FC |
+	    MAC_CFG_SPEED_MASK);
+	if ((ctlr->did == attansic_l1d ||
+	    ctlr->did == attansic_l1d_1 ||
+	    ctlr->did == attansic_l2c_2 ||
+	    ctlr->flags & alcfl_ar816x) != 0)
+		reg |= MAC_CFG_HASH_ALG_CRC32 | MAC_CFG_SPEED_MODE_SW;
+	/* Reprogram MAC with resolved speed/duplex. */
+	switch (phy->speed) {
+	case 10:
+	case 100:
+		reg |= MAC_CFG_SPEED_10_100;
+		break;
+	case 1000:
+		reg |= MAC_CFG_SPEED_1000;
+		break;
+	}
+	if (phy->fd) {
+		reg |= MAC_CFG_FULL_DUPLEX;
+		if (phy->tfc != 0)
+			reg |= MAC_CFG_TX_FC;
+		if (phy->rfc != 0)
+			reg |= MAC_CFG_RX_FC;
+	}
+	csr32w(ctlr, ALC_MAC_CFG, reg);
+}
+
+
+static void
+mac_stop(Ctlr *ctlr)
+{
+	uint reg;
+	int i;
+
+	queue_stop(ctlr);
+	/* Disable Rx/Tx MAC. */
+	reg = csr32r(ctlr, ALC_MAC_CFG);
+	if ((reg & (MAC_CFG_TX_ENB | MAC_CFG_RX_ENB)) != 0) {
+		reg &= ~(MAC_CFG_TX_ENB | MAC_CFG_RX_ENB);
+		csr32w(ctlr, ALC_MAC_CFG, reg);
+	}
+	for (i = ALC_TIMEOUT; i > 0; i--) {
+		reg = csr32r(ctlr, ALC_IDLE_STATUS);
+		if ((reg & (IDLE_STATUS_RXMAC | IDLE_STATUS_TXMAC)) == 0)
+			break;
+		microdelay(10);
+	}
+	if (i == 0)
+		print("%s: could not disable Rx/Tx MAC(0x%08x)!\n", ctlr->edev->name, reg);
+}
+
+static void
+osc_reset(Ctlr *ctlr)
+{
+	uint reg;
+
+	reg = csr32r(ctlr, ALC_MISC3);
+	reg &= ~MISC3_25M_BY_SW;
+	reg |= MISC3_25M_NOTO_INTNL;
+	csr32w(ctlr, ALC_MISC3, reg);
+	reg = csr32r(ctlr, ALC_MISC);
+	if ((ctlr->rid>>3) >= AR816X_REV_B0) {
+		/*
+		 * Restore over-current protection default value.
+		 * This value could be reset by MAC reset.
+		 */
+		reg &= ~MISC_PSW_OCP_MASK;
+		reg |= (MISC_PSW_OCP_DEFAULT << MISC_PSW_OCP_SHIFT);
+		reg &= ~MISC_INTNLOSC_OPEN;
+		csr32w(ctlr, ALC_MISC, reg);
+		csr32w(ctlr, ALC_MISC, reg | MISC_INTNLOSC_OPEN);
+		reg = csr32r(ctlr, ALC_MISC2);
+		reg &= ~MISC2_CALB_START;
+		csr32w(ctlr, ALC_MISC2, reg);
+		csr32w(ctlr, ALC_MISC2, reg | MISC2_CALB_START);
+	} else {
+		reg &= ~MISC_INTNLOSC_OPEN;
+		/* Disable isolate for revision A devices. */
+		if ((ctlr->rid>>3) <= AR816X_REV_A1)
+			reg &= ~MISC_ISO_ENB;
+		csr32w(ctlr, ALC_MISC, reg | MISC_INTNLOSC_OPEN);
+		csr32w(ctlr, ALC_MISC, reg);
+	}
+	microdelay(20);
+}
+
+static void
+alc_reset(Ctlr *ctlr)
+{
+	uint reg, pmcfg = 0;
+	int i;
+	if ((ctlr->flags & alcfl_ar816x) != 0) {
+		/* Reset workaround. */
+	        csr32w(ctlr, ALC_MBOX_RD0_PROD_IDX, 1);
+		if ((ctlr->rid>>3) <= AR816X_REV_A1 &&
+		    ((ctlr->rid>>3) & 0x01) != 0) {
+			/* Disable L0s/L1s before reset. */
+			pmcfg = csr32r(ctlr, ALC_PM_CFG);
+			if ((pmcfg & (PM_CFG_ASPM_L0S_ENB |
+			    PM_CFG_ASPM_L1_ENB))!= 0) {
+				pmcfg &= ~(PM_CFG_ASPM_L0S_ENB |
+				    PM_CFG_ASPM_L1_ENB);
+				csr32w(ctlr, ALC_PM_CFG, pmcfg);
+			}
+		}
+	}
+	reg = csr32r(ctlr, ALC_MASTER_CFG);
+	reg |= MASTER_OOB_DIS_OFF | MASTER_RESET;
+	csr32w(ctlr, ALC_MASTER_CFG, reg);
+
+	if ((ctlr->flags & alcfl_ar816x) != 0) {
+		for (i = ALC_RESET_TIMEOUT; i > 0; i--) {
+			microdelay(10);
+			if (csr32r(ctlr, ALC_MBOX_RD0_PROD_IDX) == 0)
+				break;
+		}
+		if (i == 0)
+			print("MAC reset timeout!\n");
+	}
+	for (i = ALC_RESET_TIMEOUT; i > 0; i--) {
+		microdelay(10);
+		if ((csr32r(ctlr, ALC_MASTER_CFG) & MASTER_RESET) == 0)
+			break;
+	}
+	if (i == 0)
+		print("%s: master reset timeout!\n", ctlr->edev->name);
+
+	for (i = ALC_RESET_TIMEOUT; i > 0; i--) {
+		reg = csr32r(ctlr, ALC_IDLE_STATUS);
+		if ((reg & (IDLE_STATUS_RXMAC | IDLE_STATUS_TXMAC |
+		    IDLE_STATUS_RXQ | IDLE_STATUS_TXQ)) == 0)
+			break;
+		microdelay(10);
+	}
+
+	if (i == 0)
+		print("%s: reset timeout(0x%08x)!\n", ctlr->edev->name, reg);
+
+	if ((ctlr->flags & alcfl_ar816x) != 0) {
+		if ((ctlr->rid>>3) <= AR816X_REV_A1 &&
+		    ((ctlr->rid>>3) & 0x01) != 0) {
+			reg = csr32r(ctlr, ALC_MASTER_CFG);
+			reg |= MASTER_CLK_SEL_DIS;
+			csr32w(ctlr, ALC_MASTER_CFG, reg);
+			/* Restore L0s/L1s config. */
+			if ((pmcfg & (PM_CFG_ASPM_L0S_ENB |
+			    PM_CFG_ASPM_L1_ENB)) != 0)
+				csr32w(ctlr, ALC_PM_CFG, pmcfg);
+		}
+		osc_reset(ctlr);
+		reg = csr32r(ctlr, ALC_MISC3);
+		reg &= ~MISC3_25M_BY_SW;
+		reg |= MISC3_25M_NOTO_INTNL;
+		csr32w(ctlr, ALC_MISC3, reg);
+		reg = csr32r(ctlr, ALC_MISC);
+		reg &= ~MISC_INTNLOSC_OPEN;
+		if ((ctlr->rid>>3) <= AR816X_REV_A1)
+			reg &= ~MISC_ISO_ENB;
+		csr32w(ctlr, ALC_MISC, reg);
+		microdelay(20);
+	}
+	if ((ctlr->flags & alcfl_ar816x) != 0 ||
+	    ctlr->did == attansic_l2c_1 ||
+	    ctlr->did == attansic_l2c_2)
+		csr32w(ctlr, ALC_SERDES_LOCK,
+		    csr32r(ctlr, ALC_SERDES_LOCK) |
+		    SERDES_MAC_CLK_SLOWDOWN | SERDES_PHY_CLK_SLOWDOWN);
+}
+
+static int
+reset(Ctlr *ctlr)
+{
+	phy_reset(ctlr);
+	mac_stop(ctlr);
+	get_mac(ctlr);
+	alc_reset(ctlr);
+	return 0;
+}
+
+static void
+disable_l0s_l1(Ctlr *ctlr)
+{
+	uint pmcfg;
+	if ((ctlr->flags & alcfl_ar816x) != 0) {
+		return;
+	}
+	/* Another magic from vendor. */
+	pmcfg = csr32r(ctlr, ALC_PM_CFG);
+	pmcfg &= ~(PM_CFG_L1_ENTRY_TIMER_MASK | PM_CFG_CLK_SWH_L1 |
+		   PM_CFG_ASPM_L0S_ENB | PM_CFG_ASPM_L1_ENB |
+		   PM_CFG_MAC_ASPM_CHK | PM_CFG_SERDES_PD_EX_L1);
+	pmcfg |= PM_CFG_SERDES_BUDS_RX_L1_ENB |
+		PM_CFG_SERDES_PLL_L1_ENB | PM_CFG_SERDES_L1_ENB;
+	csr32w(ctlr, ALC_PM_CFG, pmcfg);
+}
+
+static uint dma_burst[] = { 128, 256, 512, 1024, 2048, 4096, 0, 0 };
+
+static void
+pcie_init(Ctlr *ctlr, int base)
+{
+	const char *aspm_state[] = { "L0s/L1", "L0s", "L1", "L0s/L1" };
+	uint val;
+	int state;
+
+	/* Clear data link and flow-control protocol error. */
+	val = csr32r(ctlr, ALC_PEX_UNC_ERR_SEV);
+	val &= ~(PEX_UNC_ERR_SEV_DLP | PEX_UNC_ERR_SEV_FCP);
+	csr32w(ctlr, ALC_PEX_UNC_ERR_SEV, val);
+
+	if ((ctlr->flags & alcfl_ar816x) == 0) {
+		uint cap, ctl;
+		csr32w(ctlr, ALC_LTSSM_ID_CFG,
+		    csr32r(ctlr, ALC_LTSSM_ID_CFG) & ~LTSSM_ID_WRO_ENB);
+		csr32w(ctlr, ALC_PCIE_PHYMISC,
+		    csr32r(ctlr, ALC_PCIE_PHYMISC) |
+		    PCIE_PHYMISC_FORCE_RCV_DET);
+		if (ctlr->did == attansic_l2c_1 &&
+		    ctlr->rid == ATHEROS_AR8152_B_V10) {
+			val = csr32r(ctlr, ALC_PCIE_PHYMISC2);
+			val &= ~(PCIE_PHYMISC2_SERDES_CDR_MASK |
+			    PCIE_PHYMISC2_SERDES_TH_MASK);
+			val |= 3 << PCIE_PHYMISC2_SERDES_CDR_SHIFT;
+			val |= 3 << PCIE_PHYMISC2_SERDES_TH_SHIFT;
+			csr32w(ctlr, ALC_PCIE_PHYMISC2, val);
+		}
+		/* Disable ASPM L0S and L1. */
+		cap = pcicfgr32(ctlr->pcidev, base + 0xc) >> 16;
+		if ((cap & 0x00000c00) != 0) {
+			ctl = pcicfgr32(ctlr->pcidev, base + 0x10) >> 16;
+			if ((ctl & 0x08) != 0)
+				ctlr->rcb = DMA_CFG_RCB_128;
+			print("%s: RCB %d bytes\n",
+			      ctlr->edev->name,
+			      ctlr->rcb == DMA_CFG_RCB_64 ? 64 : 128);
+			state = ctl & 0x03;
+			if (state & 0x01)
+				ctlr->flags |= alcfl_l0s;
+			if (state & 0x02)
+				ctlr->flags |= alcfl_l1s;
+			print("%s: ASPM %s %s\n",
+			      ctlr->edev->name,
+			      aspm_state[state],
+			      state == 0 ? "disabled" : "enabled");
+			disable_l0s_l1(ctlr);
+		}
+	} else {
+		val = csr32r(ctlr, ALC_PDLL_TRNS1);
+		val &= ~PDLL_TRNS1_D3PLLOFF_ENB;
+		csr32w(ctlr, ALC_PDLL_TRNS1, val);
+		val = csr32r(ctlr, ALC_MASTER_CFG);
+		if (AR816X_REV(ctlr->rid) <= AR816X_REV_A1 &&
+		    (ctlr->rid & 0x01) != 0) {
+			if ((val & MASTER_WAKEN_25M) == 0 ||
+			    (val & MASTER_CLK_SEL_DIS) == 0) {
+				val |= MASTER_WAKEN_25M | MASTER_CLK_SEL_DIS;
+				csr32w(ctlr, ALC_MASTER_CFG, val);
+			}
+		} else {
+			if ((val & MASTER_WAKEN_25M) == 0 ||
+			    (val & MASTER_CLK_SEL_DIS) != 0) {
+				val |= MASTER_WAKEN_25M;
+				val &= ~MASTER_CLK_SEL_DIS;
+				csr32w(ctlr, ALC_MASTER_CFG, val);
+			}
+		}
+	}
+}
+
+static void
+alcpci(Ether *edev)
+{
+	MiiPhy *phy;
+	Pcidev *p;
+	Ctlr *ctlr;
+	void *mem;
+	int flags, burst;
+	int capoff;
+	p = nil;
+	while(p = pcimatch(p, 0, 0)){
+		if(p->ccrb != 0x02 || p->ccru != 0)
+			continue;
+		if(p->mem[0].bar & 1)
+			continue;
+		flags = 0;
+		switch((p->did<<16)|p->vid){
+		default:
+			continue;
+		case attansic_e2200:
+		case attansic_e2400:
+		case attansic_e2500:
+			flags |= alcfl_e2x00;
+		case attansic_ar8161:
+			if ((p->rid>>3) == 0)
+				flags |= alcfl_link_war;
+		case attansic_ar8171:
+			flags |= alcfl_ar816x;
+			break;
+		case attansic_ar8162:
+		case attansic_ar8172:
+			flags |= alcfl_fasteth | alcfl_ar816x;
+			break;
+		case attansic_l2c_1:
+		case attansic_l2c_2:
+			flags |= alcfl_aps;
+		case attansic_l2c: /* eeepc 1000px */
+			flags |= alcfl_fasteth;
+			break;
+		case attansic_l1d:
+		case attansic_l1d_1:
+			flags |= alcfl_aps;
+		case attansic_l1e:
+		case attansic_l1:
+		case attansic_l1c:
+		case attansic_l2:
+			break;
+		}
+		flags |= alcfl_jumbo;
+		mem = vmap(p->mem[0].bar & ~0xF, p->mem[0].size);
+		if(mem == nil){
+			print("alc: can't map %llux\n", p->mem[0].bar & ~0xF);
+			continue;
+		}
+		ctlr = malloc(sizeof(Ctlr));
+		if (ctlr == nil) {
+			print("alc: can't allocate memory\n");
+			continue;
+		}
+		ctlr->edev = edev;
+		ctlr->flags = flags;
+		ctlr->phy = 0;
+		ctlr->port = p->mem[0].bar & ~0x0F;
+		ctlr->pcidev = p;
+		ctlr->did = (p->did<<16)|p->vid;
+		pcienable(p);
+		//		ctlr->cls = p->cls*4;
+		ctlr->mem = mem;
+		ctlr->rid = p->rid;
+		capoff = pcicap(p, PciCapPCIe);
+		if (capoff >=0) {
+			ctlr->flags |= alcfl_pcie;
+			ctlr->excap = capoff;
+			burst = csr16r(ctlr, capoff + 0x08);
+			ctlr->dma_rd_burst = (burst & 0x7000) >> 12;
+			ctlr->dma_wr_burst = (burst & 0x00e0) >> 5;
+			if (dma_burst[ctlr->dma_rd_burst] > 1024)
+				ctlr->dma_rd_burst = 3;
+			if (dma_burst[ctlr->dma_wr_burst] > 1024)
+				ctlr->dma_wr_burst = 3;
+			if ((ctlr->flags & alcfl_e2x00) != 0)
+				ctlr->dma_wr_burst = 0;
+			pcie_init(ctlr, capoff);
+		}
+		if (reset(ctlr)) {
+			free(ctlr);
+			vunmap(mem, p->mem[0].size);
+			continue;
+		}
+		ctlr->mii = malloc(sizeof(Mii));
+		if (ctlr->mii == nil) {
+			print("alc: can not allocate memory\n");
+			free(ctlr);
+			vunmap(mem, p->mem[0].size);
+			continue;
+		}
+		ctlr->mii->ctlr = ctlr;
+		ctlr->mii->mir = phy_mii_read;
+		ctlr->mii->miw = phy_mii_write;
+		if (mii(ctlr->mii, 1) == 0 || (phy = ctlr->mii->curphy) == nil) {
+			print("alc: can not found phy\n");
+			free(ctlr->mii);
+			free(ctlr);
+			vunmap(mem, p->mem[0].size);
+			continue;
+		}
+		USED(phy);
+		pcisetbme(p);
+		if (alcctlrhead != nil)
+			alcctlrtail->next = ctlr;
+		else
+			alcctlrhead = ctlr;
+		alcctlrtail = ctlr;
+	}
+}
+
+static void
+rxrefill(Ctlr* ctlr)
+{
+	RxDesc *rd;
+	int rdt;
+	Block *bp;
+
+	rdt = ctlr->rdt;
+	while (NEXT(rdt, DSCN) != ctlr->rdh) {
+		rd = &ctlr->rx_ring[rdt];
+		if (ctlr->rb[rdt] == nil) {
+			bp = allocb(RX_BUF_SIZE_MAX);
+			bp->rp = bp->lim - RX_BUF_SIZE_MAX;
+			bp->wp = bp->rp;
+			ctlr->rb[rdt] = bp;
+			rd->addr = PCIWADDR(bp->rp); /* todo le/be? */
+		}
+		memset(&ctlr->rrx_ring[rdt], 0, sizeof(RxRdesc));
+		coherence();
+		rdt = NEXT(rdt, DSCN);
+		ctlr->rdfree++;
+	}
+	ctlr->rdt = rdt;
+	if ((ctlr->flags & alcfl_ar816x) != 0) {
+		csr16w(ctlr, ALC_MBOX_RD0_PROD_IDX, (ushort)ctlr->rdt);
+	} else {
+		csr32w(ctlr, ALC_MBOX_RD0_PROD_IDX, ctlr->rdt);
+	}
+}
+
+static int
+rxinit(Ctlr *ctlr)
+{
+	int i;
+	Block *bp;
+
+	for (i=0; i<DSCN; i++) {
+		if ((bp = ctlr->rb[i]) != nil) {
+			ctlr->rb[i] = nil;
+			freeb(bp);
+		}
+		memset(&ctlr->rx_ring[i], 0, sizeof(RxDesc));
+		memset(&ctlr->rrx_ring[i], 0, sizeof(RxRdesc));
+	}
+	ctlr->rdfree = 0;
+	rxrefill(ctlr);
+	return 0;
+}
+
+static int
+txinit(Ctlr *ctlr)
+{
+	int i;
+	Block *bp;
+
+	for (i=0; i<DSCN; i++) {
+		if ((bp = ctlr->tb[i]) != nil) {
+			ctlr->tb[i] = nil;
+			freeb(bp);
+		}
+		memset(&ctlr->tx_ring[i], 0, sizeof(TxDesc));
+	}
+	ctlr->tdfree = DSCN;
+	return 0;
+}
+
+static void
+stats_clear(Ctlr *ctlr)
+{
+	int i;
+	for (i = 0; i < 24; i++) {
+		csr32r(ctlr, ALC_RX_MIB_BASE + i*4);
+	}
+	/* Read Tx statistics. */
+	for (i = 0; i < 25; i++) {
+		csr32r(ctlr, ALC_TX_MIB_BASE + i*4);
+	}
+}
+
+static void
+alc_promisc(void *arg, int on)
+{
+	int rxcfg;
+	Ctlr *ctlr;
+	Ether *edev;
+	edev = arg;
+	ctlr = edev->ctlr;
+	rxcfg = csr32r(ctlr, ALC_MAC_CFG);
+	if (on) {
+		rxcfg |= MAC_CFG_PROMISC;
+	} else {
+		rxcfg &= ~MAC_CFG_PROMISC;
+	}
+	csr32w(ctlr, ALC_MAC_CFG, rxcfg);
+}
+
+static int
+alclim(void* ctlr)
+{
+	return ((Ctlr*)ctlr)->lim != 0;
+}
+
+static int
+alcrim(void* ctlr)
+{
+	return ((Ctlr*)ctlr)->rim != 0;
+}
+
+static void
+rproc(void *arg)
+{
+	RxRdesc *rrd;
+	Block *bp;
+	Ctlr *ctlr;
+	int rdh, nsegs;
+	uint status;
+	Ether *edev;
+
+	edev = arg;
+	ctlr = edev->ctlr;
+
+	for(;;) {
+		ctlr->rim = 0;
+		sleep(&ctlr->rrendez, alcrim, ctlr);
+		rdh = ctlr->rdh;
+		for(;;) {
+			rrd = &ctlr->rrx_ring[rdh];
+			status = letoh32(rrd->status);
+			if ((status & RRD_VALID) == 0)
+				break;
+			nsegs = RRD_RD_CNT(letoh32(rrd->rdinfo));
+			if (nsegs != 1) {
+				print("%s: unexpected segment count\n", ctlr->edev->name);
+				continue;
+			}
+			if ((status &
+			     (RRD_ERR_CRC | RRD_ERR_ALIGN |
+			      RRD_ERR_TRUNC | RRD_ERR_RUNT)) == 0) {
+				bp = ctlr->rb[rdh];
+				ctlr->rb[rdh] = nil;
+				bp->wp += RRD_BYTES(status);
+				bp->next = nil;
+				etheriq(edev, bp);
+			} else if (ctlr->rb[rdh] != nil) {
+				freeb(ctlr->rb[rdh]);
+				ctlr->rb[rdh] = nil;
+			}
+			rrd->status = 0;
+			memset(&ctlr->rx_ring[rdh], 0, sizeof(RxDesc));
+			coherence();
+			ctlr->rdfree --;
+			rdh = NEXT(rdh, DSCN);
+		}
+		ctlr->rdh = rdh;
+		if (ctlr->rdfree < DSCN/2)
+			rxrefill(ctlr);
+	}
+}
+
+static void
+aspm_813x(Ctlr *ctlr, int speed)
+{
+	uint pmcfg;
+	uint linkcfg;
+
+	pmcfg = csr32r(ctlr, ALC_PM_CFG);
+	if ((ctlr->flags & (alcfl_aps | alcfl_pcie)) ==
+	    (alcfl_aps | alcfl_pcie))
+		linkcfg = csr16r(ctlr, ctlr->excap + 0x10);
+	else
+		linkcfg = 0;
+	pmcfg &= ~PM_CFG_SERDES_PD_EX_L1;
+	pmcfg &= ~(PM_CFG_L1_ENTRY_TIMER_MASK | PM_CFG_LCKDET_TIMER_MASK);
+	pmcfg |= PM_CFG_MAC_ASPM_CHK;
+	pmcfg |= (PM_CFG_LCKDET_TIMER_DEFAULT << PM_CFG_LCKDET_TIMER_SHIFT);
+	pmcfg &= ~(PM_CFG_ASPM_L1_ENB | PM_CFG_ASPM_L0S_ENB);
+
+	if ((ctlr->flags & alcfl_aps) != 0) {
+		/* Disable extended sync except AR8152 B v1.0 */
+		linkcfg &= ~0x80;
+		if (ctlr->did == attansic_l2c_1 &&
+		    ctlr->rid == ATHEROS_AR8152_B_V10)
+			linkcfg |= 0x80;
+		csr16w(ctlr, ctlr->excap + 0x10, linkcfg);
+		pmcfg &= ~(PM_CFG_EN_BUFS_RX_L0S | PM_CFG_SA_DLY_ENB |
+		    PM_CFG_HOTRST);
+		pmcfg |= (PM_CFG_L1_ENTRY_TIMER_DEFAULT <<
+		    PM_CFG_L1_ENTRY_TIMER_SHIFT);
+		pmcfg &= ~PM_CFG_PM_REQ_TIMER_MASK;
+		pmcfg |= (PM_CFG_PM_REQ_TIMER_DEFAULT <<
+		    PM_CFG_PM_REQ_TIMER_SHIFT);
+		pmcfg |= PM_CFG_SERDES_PD_EX_L1 | PM_CFG_PCIE_RECV;
+	}
+
+	if ((ctlr->flags & alcfl_link) != 0) {
+		if ((ctlr->flags & alcfl_l0s) != 0)
+			pmcfg |= PM_CFG_ASPM_L0S_ENB;
+		if ((ctlr->flags & alcfl_l1s) != 0)
+			pmcfg |= PM_CFG_ASPM_L1_ENB;
+		if ((ctlr->flags & alcfl_aps) != 0) {
+			if (ctlr->did == attansic_l2c_1)
+				pmcfg &= ~PM_CFG_ASPM_L0S_ENB;
+			pmcfg &= ~(PM_CFG_SERDES_L1_ENB |
+			    PM_CFG_SERDES_PLL_L1_ENB |
+			    PM_CFG_SERDES_BUDS_RX_L1_ENB);
+			pmcfg |= PM_CFG_CLK_SWH_L1;
+			if (speed == 100 || speed == 1000) {
+				pmcfg &= ~PM_CFG_L1_ENTRY_TIMER_MASK;
+				switch (ctlr->did) {
+				case attansic_l2c_1:
+					pmcfg |= (7 <<
+					    PM_CFG_L1_ENTRY_TIMER_SHIFT);
+					break;
+				case attansic_l1d_1:
+				case attansic_l2c_2:
+					pmcfg |= (4 <<
+					    PM_CFG_L1_ENTRY_TIMER_SHIFT);
+					break;
+				default:
+					pmcfg |= (15 <<
+					    PM_CFG_L1_ENTRY_TIMER_SHIFT);
+					break;
+				}
+			}
+		} else {
+			pmcfg |= PM_CFG_SERDES_L1_ENB |
+			    PM_CFG_SERDES_PLL_L1_ENB |
+			    PM_CFG_SERDES_BUDS_RX_L1_ENB;
+			pmcfg &= ~(PM_CFG_CLK_SWH_L1 |
+			    PM_CFG_ASPM_L1_ENB | PM_CFG_ASPM_L0S_ENB);
+		}
+	} else {
+		pmcfg &= ~(PM_CFG_SERDES_BUDS_RX_L1_ENB | PM_CFG_SERDES_L1_ENB |
+		    PM_CFG_SERDES_PLL_L1_ENB);
+		pmcfg |= PM_CFG_CLK_SWH_L1;
+		if ((ctlr->flags & alcfl_l1s) != 0)
+			pmcfg |= PM_CFG_ASPM_L1_ENB;
+	}
+	csr32w(ctlr, ALC_PM_CFG, pmcfg);
+}
+
+static void
+aspm_816x(Ctlr *ctlr, int init)
+{
+	uint pmcfg;
+
+	pmcfg = csr32r(ctlr, ALC_PM_CFG);
+	pmcfg &= ~PM_CFG_L1_ENTRY_TIMER_816X_MASK;
+	pmcfg |= PM_CFG_L1_ENTRY_TIMER_816X_DEFAULT;
+	pmcfg &= ~PM_CFG_PM_REQ_TIMER_MASK;
+	pmcfg |= PM_CFG_PM_REQ_TIMER_816X_DEFAULT;
+	pmcfg &= ~PM_CFG_LCKDET_TIMER_MASK;
+	pmcfg |= PM_CFG_LCKDET_TIMER_DEFAULT;
+	pmcfg |= PM_CFG_SERDES_PD_EX_L1 | PM_CFG_CLK_SWH_L1 | PM_CFG_PCIE_RECV;
+	pmcfg &= ~(PM_CFG_RX_L1_AFTER_L0S | PM_CFG_TX_L1_AFTER_L0S |
+	    PM_CFG_ASPM_L1_ENB | PM_CFG_ASPM_L0S_ENB |
+	    PM_CFG_SERDES_L1_ENB | PM_CFG_SERDES_PLL_L1_ENB |
+	    PM_CFG_SERDES_BUDS_RX_L1_ENB | PM_CFG_SA_DLY_ENB |
+	    PM_CFG_MAC_ASPM_CHK | PM_CFG_HOTRST);
+	if (AR816X_REV(ctlr->rid) <= AR816X_REV_A1 &&
+	    (ctlr->rid & 0x01) != 0)
+		pmcfg |= PM_CFG_SERDES_L1_ENB | PM_CFG_SERDES_PLL_L1_ENB;
+	if ((ctlr->flags & alcfl_link) != 0) {
+		/* Link up, enable both L0s, L1s. */
+		pmcfg |= PM_CFG_ASPM_L0S_ENB | PM_CFG_ASPM_L1_ENB |
+		    PM_CFG_MAC_ASPM_CHK;
+	} else {
+		if (init != 0)
+			pmcfg |= PM_CFG_ASPM_L0S_ENB | PM_CFG_ASPM_L1_ENB |
+			    PM_CFG_MAC_ASPM_CHK;
+		else
+			pmcfg |= PM_CFG_ASPM_L1_ENB | PM_CFG_MAC_ASPM_CHK;
+	}
+	csr32w(ctlr, ALC_PM_CFG, pmcfg);
+}
+
+static void
+aspm(Ctlr *ctlr, int init, int speed)
+{
+	if ((ctlr->flags & alcfl_ar816x) != 0)
+		aspm_816x(ctlr, init);
+	else
+		aspm_813x(ctlr, speed);
+}
+
+static void
+lproc(void *arg)
+{
+	Ctlr *ctlr;
+	Ether *edev;
+	MiiPhy *phy;
+	//	int ctrl, r;
+	uint reg;
+
+	edev = arg;
+	ctlr = edev->ctlr;
+	for(;;){
+		if(ctlr->mii == nil || ctlr->mii->curphy == nil)
+			goto skip;
+		miistatus(ctlr->mii);
+		mac_stop(ctlr);
+		phy = ctlr->mii->curphy;
+		if (phy->link) {
+			ctlr->flags |= alcfl_link;
+			// print("%s: link up\n", edev->name);
+		} else {
+			ctlr->flags &= ~alcfl_link;
+			// print("%s: link down\n", edev->name);
+		}
+		if ((ctlr->flags & alcfl_link) != 0) {
+			queue_start(ctlr);
+			mac_config(ctlr);
+			reg = csr32r(ctlr, ALC_MAC_CFG);
+			reg |= MAC_CFG_TX_ENB | MAC_CFG_RX_ENB;
+			csr32w(ctlr, ALC_MAC_CFG, reg);
+		}
+		aspm(ctlr, 0, phy->speed);
+	skip:
+		ctlr->lim = 0;
+		sleep(&ctlr->lrendez, alclim, ctlr);
+	}
+}
+#define	TD_EOP	0x80000000
+
+static void
+alc_transmit(Ether* edev)
+{
+	TxDesc *td;
+	Block *bp;
+	Ctlr *ctlr;
+	int tdh, tdt, prod;
+
+	ctlr = edev->ctlr;
+
+	ilock(&ctlr->tlock);
+
+	/*
+	 * Free any completed packets
+	 */
+	tdh = ctlr->tdh;
+	if ((ctlr->flags & alcfl_ar816x) != 0) {
+		prod = csr16r(ctlr, ALC_MBOX_TD_PRI0_CONS_IDX);
+	} else {
+		prod = csr32r(ctlr, ALC_MBOX_TD_CONS_IDX);
+		prod = (prod & MBOX_TD_CONS_LO_IDX_MASK) >>
+			MBOX_TD_CONS_LO_IDX_SHIFT;
+	}
+	while (NEXT(tdh, DSCN) != prod) {
+		if((bp = ctlr->tb[tdh]) != nil){
+			ctlr->tb[tdh] = nil;
+			freeb(bp);
+		}
+		memset(&ctlr->tx_ring[tdh], 0, sizeof(TxDesc));
+		tdh = NEXT(tdh, DSCN);
+	}
+	ctlr->tdh = tdh;
+
+	/*
+	 * Try to fill the ring back up.
+	 */
+	tdt = ctlr->tdt;
+	prod = 0;
+	while(NEXT(tdt, DSCN) != tdh){
+		if((bp = qget(edev->oq)) == nil)
+			break;
+		prod ++;
+		td = &ctlr->tx_ring[tdt];
+		td->addr = PCIWADDR(bp->rp);
+		td->len = htole32(BLEN(bp));
+		td->flags = 0;
+		ctlr->tb[tdt] = bp;
+		tdt = NEXT(tdt, DSCN);
+		ctlr->tdt = tdt;
+		td = &ctlr->tx_ring[(tdt + DSCN - 1) % DSCN];
+		td->flags |= htole32(TD_EOP);
+	}
+	if (prod > 0) {
+		if ((ctlr->flags & alcfl_ar816x) != 0)
+			csr16w(ctlr, ALC_MBOX_TD_PRI0_PROD_IDX, tdt);
+		else
+			csr32w(ctlr, ALC_MBOX_TD_PROD_IDX,
+			       (tdt << MBOX_TD_PROD_LO_IDX_SHIFT) &
+			       MBOX_TD_PROD_LO_IDX_MASK);
+	}
+	iunlock(&ctlr->tlock);
+}
+
+static void
+alc_attach(Ether *edev)
+{
+	Ctlr *ctlr;
+	ulong pa;
+	uint reg, rxf_lo, rxf_hi;
+	uchar *eaddr;
+	char name[KNAMELEN];
+	ctlr = edev->ctlr;
+	qlock(&ctlr->alock);
+	if (ctlr->tx_ring != nil) {
+		qunlock(&ctlr->alock);
+		return;
+	}
+	ctlr->tx_ring = mallocalign(sizeof(TxDesc) * DSCN, 8, 0, 0);
+	if (ctlr->tx_ring == nil)
+		goto memerr;
+	ctlr->rx_ring = mallocalign(sizeof(RxDesc) * DSCN, 8, 0, 0);
+	if (ctlr->rx_ring == nil)
+		goto memerr;
+	ctlr->rrx_ring = mallocalign(sizeof(RxRdesc) * DSCN, 8, 0, 0);
+	if (ctlr->rrx_ring == nil)
+		goto memerr;
+	ctlr->tb = malloc(sizeof(Block*) * DSCN);
+	if (ctlr->tb == nil)
+		goto memerr;
+	ctlr->rb = malloc(sizeof(Block*) * DSCN);
+	if (ctlr->rb == nil)
+		goto memerr;
+	if (rxinit(ctlr) || txinit(ctlr)) {
+		print("%s: can not init queues\n", ctlr->edev->name);
+		goto out;
+	}
+	snprint(name, KNAMELEN, "#l%dlproc", edev->ctlrno);
+	kproc(name, lproc, edev);
+
+	snprint(name, KNAMELEN, "#l%drproc", edev->ctlrno);
+	kproc(name, rproc, edev);
+
+	csr32w(ctlr, ALC_MBOX_RD0_PROD_IDX, DSCN - 1);
+
+	/* Enable all clocks. */
+	if ((ctlr->flags & alcfl_ar816x) != 0) {
+		csr32w(ctlr, ALC_CLK_GATING_CFG, CLK_GATING_DMAW_ENB |
+		    CLK_GATING_DMAR_ENB | CLK_GATING_TXQ_ENB |
+		    CLK_GATING_RXQ_ENB | CLK_GATING_TXMAC_ENB |
+		    CLK_GATING_RXMAC_ENB);
+		if (AR816X_REV(ctlr->rid) >= AR816X_REV_B0)
+			csr32w(ctlr, ALC_IDLE_DECISN_TIMER,
+			    IDLE_DECISN_TIMER_DEFAULT_1MS);
+	} else
+		csr32w(ctlr, ALC_CLK_GATING_CFG, 0);
+	/* Reprogram the station address. */
+	eaddr = ctlr->ra;
+	csr32w(ctlr, ALC_PAR0, eaddr[2] << 24 | eaddr[3] << 16 | eaddr[4] << 8 | eaddr[5]);
+	csr32w(ctlr, ALC_PAR1, eaddr[0] << 8 | eaddr[1]);
+	/*
+	 * Clear WOL status and disable all WOL feature as WOL
+	 * would interfere Rx operation under normal environments.
+	 */
+	csr32r(ctlr, ALC_WOL_CFG);
+	csr32w(ctlr, ALC_WOL_CFG, 0);
+	/* Set Tx descriptor base addresses. */
+	pa = PCIWADDR(ctlr->tx_ring);
+	csr32w(ctlr, ALC_TX_BASE_ADDR_HI, HI(pa));
+	csr32w(ctlr, ALC_TDL_HEAD_ADDR_LO, LO(pa));
+	/* We don't use high priority ring. */
+	csr32w(ctlr, ALC_TDH_HEAD_ADDR_LO, 0);
+	/* Set Tx descriptor counter. */
+	csr32w(ctlr, ALC_TD_RING_CNT,
+	       (DSCN << TD_RING_CNT_SHIFT) & TD_RING_CNT_MASK);
+	/* Set Rx descriptor base addresses. */
+	pa = PCIWADDR(ctlr->rx_ring);
+	csr32w(ctlr, ALC_RX_BASE_ADDR_HI, HI(pa));
+	csr32w(ctlr, ALC_RD0_HEAD_ADDR_LO, LO(pa));
+	if ((ctlr->flags & alcfl_ar816x) == 0) {
+		/* We use one Rx ring. */
+		csr32w(ctlr, ALC_RD1_HEAD_ADDR_LO, 0);
+		csr32w(ctlr, ALC_RD2_HEAD_ADDR_LO, 0);
+		csr32w(ctlr, ALC_RD3_HEAD_ADDR_LO, 0);
+	}
+	/* Set Rx descriptor counter. */
+	csr32w(ctlr, ALC_RD_RING_CNT,
+	    (DSCN << RD_RING_CNT_SHIFT) & RD_RING_CNT_MASK);
+
+	csr32w(ctlr, ALC_RX_BUF_SIZE, RX_BUF_SIZE_MAX);
+	pa = PCIWADDR(ctlr->rrx_ring);
+
+	/* Set Rx return descriptor base addresses. */
+	csr32w(ctlr, ALC_RRD0_HEAD_ADDR_LO, LO(pa));
+	if ((ctlr->flags & alcfl_ar816x) == 0) {
+		/* We use one Rx return ring. */
+		csr32w(ctlr, ALC_RRD1_HEAD_ADDR_LO, 0);
+		csr32w(ctlr, ALC_RRD2_HEAD_ADDR_LO, 0);
+		csr32w(ctlr, ALC_RRD3_HEAD_ADDR_LO, 0);
+	}
+
+	/* Set Rx return descriptor counter. */
+	csr32w(ctlr, ALC_RRD_RING_CNT,
+	    (DSCN << RRD_RING_CNT_SHIFT) & RRD_RING_CNT_MASK);
+
+	if (ctlr->did == attansic_l2c_1) {
+		/* Reconfigure SRAM - Vendor magic. */
+	        csr32w(ctlr, ALC_SRAM_RX_FIFO_LEN, 0x000002A0);
+		csr32w(ctlr, ALC_SRAM_TX_FIFO_LEN, 0x00000100);
+		csr32w(ctlr, ALC_SRAM_RX_FIFO_ADDR, 0x029F0000);
+		csr32w(ctlr, ALC_SRAM_RD0_ADDR, 0x02BF02A0);
+		csr32w(ctlr, ALC_SRAM_TX_FIFO_ADDR, 0x03BF02C0);
+		csr32w(ctlr, ALC_SRAM_TD_ADDR, 0x03DF03C0);
+		csr32w(ctlr, ALC_TXF_WATER_MARK, 0x00000000);
+		csr32w(ctlr, ALC_RD_DMA_CFG, 0x00000000);
+	}
+
+	/* Tell hardware that we're ready to load DMA blocks. */
+	csr32w(ctlr, ALC_DMA_BLOCK, DMA_BLOCK_LOAD);
+
+	/* Configure interrupt moderation timer. */
+	reg = ALC_USECS(ALC_IM_RX_TIMER_DEFAULT) << IM_TIMER_RX_SHIFT;
+	if ((ctlr->flags & alcfl_ar816x) == 0)
+	    reg |= ALC_USECS(ALC_IM_TX_TIMER_DEFAULT) << IM_TIMER_TX_SHIFT;
+	csr32w(ctlr, ALC_IM_TIMER, reg);
+	/*
+	 * We don't want to automatic interrupt clear as task queue
+	 * for the interrupt should know interrupt status.
+	 */
+	reg = csr32r(ctlr, ALC_MASTER_CFG);
+	reg &= ~(MASTER_IM_RX_TIMER_ENB | MASTER_IM_TX_TIMER_ENB);
+	reg |= MASTER_SA_TIMER_ENB;
+	reg |= MASTER_IM_RX_TIMER_ENB;
+	if ((ctlr->flags & alcfl_ar816x) == 0)
+		reg |= MASTER_IM_TX_TIMER_ENB;
+	csr32w(ctlr, ALC_MASTER_CFG, reg);
+	/*
+	 * Disable interrupt re-trigger timer. We don't want automatic
+	 * re-triggering of un-ACKed interrupts.
+	 */
+	csr32w(ctlr, ALC_INTR_RETRIG_TIMER, ALC_USECS(0));
+	/* Configure CMB. */
+	if ((ctlr->flags & alcfl_ar816x) != 0) {
+		csr32w(ctlr, ALC_CMB_TD_THRESH, 0);
+	}
+	csr32w(ctlr, ALC_CMB_TX_TIMER, ALC_USECS(0));
+	csr32w(ctlr, ALC_SMB_STAT_TIMER, ALC_USECS(0));
+	/* Clear MAC statistics. */
+	stats_clear(ctlr);
+	csr32w(ctlr, ALC_FRAME_SIZE, RX_BUF_SIZE_MAX);
+
+	if ((ctlr->flags & alcfl_ar816x) == 0) {
+		/* Disable header split(?) */
+		csr32w(ctlr, ALC_HDS_CFG, 0);
+		/* Configure IPG/IFG parameters. */
+		csr32w(ctlr, ALC_IPG_IFG_CFG,
+		    ((IPG_IFG_IPGT_DEFAULT << IPG_IFG_IPGT_SHIFT) &
+		    IPG_IFG_IPGT_MASK) |
+		    ((IPG_IFG_MIFG_DEFAULT << IPG_IFG_MIFG_SHIFT) &
+		    IPG_IFG_MIFG_MASK) |
+		    ((IPG_IFG_IPG1_DEFAULT << IPG_IFG_IPG1_SHIFT) &
+		    IPG_IFG_IPG1_MASK) |
+		    ((IPG_IFG_IPG2_DEFAULT << IPG_IFG_IPG2_SHIFT) &
+		    IPG_IFG_IPG2_MASK));
+		/* Set parameters for half-duplex media. */
+		csr32w(ctlr, ALC_HDPX_CFG,
+		    ((HDPX_CFG_LCOL_DEFAULT << HDPX_CFG_LCOL_SHIFT) &
+		    HDPX_CFG_LCOL_MASK) |
+		    ((HDPX_CFG_RETRY_DEFAULT << HDPX_CFG_RETRY_SHIFT) &
+		    HDPX_CFG_RETRY_MASK) | HDPX_CFG_EXC_DEF_EN |
+		    ((HDPX_CFG_ABEBT_DEFAULT << HDPX_CFG_ABEBT_SHIFT) &
+		    HDPX_CFG_ABEBT_MASK) |
+		    ((HDPX_CFG_JAMIPG_DEFAULT << HDPX_CFG_JAMIPG_SHIFT) &
+		    HDPX_CFG_JAMIPG_MASK));
+	}
+
+	/*
+	 * Set TSO/checksum offload threshold. For frames that is
+	 * larger than this threshold, hardware wouldn't do
+	 * TSO/checksum offloading.
+	 */
+	reg = (RX_BUF_SIZE_MAX >> TSO_OFFLOAD_THRESH_UNIT_SHIFT) &
+	    TSO_OFFLOAD_THRESH_MASK;
+	if ((ctlr->flags & alcfl_ar816x) != 0)
+		reg |= TSO_OFFLOAD_ERRLGPKT_DROP_ENB;
+	csr32w(ctlr, ALC_TSO_OFFLOAD_THRESH, reg);
+	/* Configure TxQ. */
+	reg = (dma_burst[ctlr->dma_rd_burst] <<
+	    TXQ_CFG_TX_FIFO_BURST_SHIFT) & TXQ_CFG_TX_FIFO_BURST_MASK;
+	if (ctlr->did == attansic_l2c_1 ||
+	    ctlr->did == attansic_l2c_2)
+		reg >>= 1;
+	reg |= (TXQ_CFG_TD_BURST_DEFAULT << TXQ_CFG_TD_BURST_SHIFT) &
+	    TXQ_CFG_TD_BURST_MASK;
+	reg |= TXQ_CFG_IP_OPTION_ENB | TXQ_CFG_8023_ENB;
+	csr32w(ctlr, ALC_TXQ_CFG, reg | TXQ_CFG_ENHANCED_MODE);
+	if ((ctlr->flags & alcfl_ar816x) != 0) {
+		reg = (TXQ_CFG_TD_BURST_DEFAULT << HQTD_CFG_Q1_BURST_SHIFT |
+		    TXQ_CFG_TD_BURST_DEFAULT << HQTD_CFG_Q2_BURST_SHIFT |
+		    TXQ_CFG_TD_BURST_DEFAULT << HQTD_CFG_Q3_BURST_SHIFT |
+		    HQTD_CFG_BURST_ENB);
+		csr32w(ctlr, ALC_HQTD_CFG, reg);
+		reg = WRR_PRI_RESTRICT_NONE;
+		reg |= (WRR_PRI_DEFAULT << WRR_PRI0_SHIFT |
+		    WRR_PRI_DEFAULT << WRR_PRI1_SHIFT |
+		    WRR_PRI_DEFAULT << WRR_PRI2_SHIFT |
+		    WRR_PRI_DEFAULT << WRR_PRI3_SHIFT);
+		csr32w(ctlr, ALC_WRR, reg);
+	} else {
+		/* Configure Rx free descriptor pre-fetching. */
+		csr32w(ctlr, ALC_RX_RD_FREE_THRESH,
+		    ((RX_RD_FREE_THRESH_HI_DEFAULT <<
+		    RX_RD_FREE_THRESH_HI_SHIFT) & RX_RD_FREE_THRESH_HI_MASK) |
+		    ((RX_RD_FREE_THRESH_LO_DEFAULT <<
+		    RX_RD_FREE_THRESH_LO_SHIFT) & RX_RD_FREE_THRESH_LO_MASK));
+	}
+
+	/*
+	 * Configure flow control parameters.
+	 * XON  : 80% of Rx FIFO
+	 * XOFF : 30% of Rx FIFO
+	 */
+	if ((ctlr->flags & alcfl_ar816x) != 0) {
+		reg = csr32r(ctlr, ALC_SRAM_RX_FIFO_LEN);
+		reg &= SRAM_RX_FIFO_LEN_MASK;
+		reg *= 8;
+		if (reg > 8 * 1024)
+			reg -= RX_FIFO_PAUSE_816X_RSVD;
+		else
+		    reg -= RX_BUF_SIZE_MAX;
+		reg /= 8;
+		csr32w(ctlr, ALC_RX_FIFO_PAUSE_THRESH,
+		    ((reg << RX_FIFO_PAUSE_THRESH_LO_SHIFT) &
+		    RX_FIFO_PAUSE_THRESH_LO_MASK) |
+		    (((RX_FIFO_PAUSE_816X_RSVD / 8) <<
+		    RX_FIFO_PAUSE_THRESH_HI_SHIFT) &
+		    RX_FIFO_PAUSE_THRESH_HI_MASK));
+	} else if (ctlr->did == attansic_l1c ||
+		   ctlr->did == attansic_l2c) {
+		reg = csr32r(ctlr, ALC_SRAM_RX_FIFO_LEN);
+		rxf_hi = (reg * 8) / 10;
+		rxf_lo = (reg * 3) / 10;
+		csr32w(ctlr, ALC_RX_FIFO_PAUSE_THRESH,
+		    ((rxf_lo << RX_FIFO_PAUSE_THRESH_LO_SHIFT) &
+		    RX_FIFO_PAUSE_THRESH_LO_MASK) |
+		    ((rxf_hi << RX_FIFO_PAUSE_THRESH_HI_SHIFT) &
+		    RX_FIFO_PAUSE_THRESH_HI_MASK));
+	}
+
+	if ((ctlr->flags & alcfl_ar816x) == 0) {
+		csr32w(ctlr, ALC_RSS_IDT_TABLE0, 0);
+		csr32w(ctlr, ALC_RSS_CPU, 0);
+	}
+
+	/* Configure RxQ. */
+	reg = (RXQ_CFG_RD_BURST_DEFAULT << RXQ_CFG_RD_BURST_SHIFT) &
+	    RXQ_CFG_RD_BURST_MASK;
+	reg |= RXQ_CFG_RSS_MODE_DIS;
+	if ((ctlr->flags & alcfl_ar816x) != 0) {
+		reg |= (RXQ_CFG_816X_IDT_TBL_SIZE_DEFAULT <<
+		    RXQ_CFG_816X_IDT_TBL_SIZE_SHIFT) &
+		    RXQ_CFG_816X_IDT_TBL_SIZE_MASK;
+		if ((ctlr->flags & alcfl_fasteth) == 0)
+			reg |= RXQ_CFG_ASPM_THROUGHPUT_LIMIT_100M;
+	} else {
+		if ((ctlr->flags & alcfl_fasteth) == 0 &&
+		    ctlr->did != attansic_l1d_1)
+			reg |= RXQ_CFG_ASPM_THROUGHPUT_LIMIT_100M;
+	}
+	csr32w(ctlr, ALC_RXQ_CFG, reg);
+
+	/* Configure DMA parameters. */
+	reg = DMA_CFG_OUT_ORDER | DMA_CFG_RD_REQ_PRI;
+	reg |= ctlr->rcb;
+	reg |= DMA_CFG_SMB_DIS;
+	reg |= (ctlr->dma_rd_burst & DMA_CFG_RD_BURST_MASK) <<
+	    DMA_CFG_RD_BURST_SHIFT;
+	reg |= (ctlr->dma_wr_burst & DMA_CFG_WR_BURST_MASK) <<
+	    DMA_CFG_WR_BURST_SHIFT;
+	reg |= (DMA_CFG_RD_DELAY_CNT_DEFAULT << DMA_CFG_RD_DELAY_CNT_SHIFT) &
+	    DMA_CFG_RD_DELAY_CNT_MASK;
+	reg |= (DMA_CFG_WR_DELAY_CNT_DEFAULT << DMA_CFG_WR_DELAY_CNT_SHIFT) &
+	    DMA_CFG_WR_DELAY_CNT_MASK;
+	if ((ctlr->flags & alcfl_ar816x) != 0) {
+		switch (AR816X_REV(ctlr->rid)) {
+		case AR816X_REV_A0:
+		case AR816X_REV_A1:
+			reg |= DMA_CFG_RD_CHNL_SEL_2;
+			break;
+		case AR816X_REV_B0:
+		default:
+			reg |= DMA_CFG_RD_CHNL_SEL_4;
+			break;
+		}
+	}
+	csr32w(ctlr, ALC_DMA_CFG, reg);
+
+	/*
+	 * Configure Tx/Rx MACs.
+	 *  - Auto-padding for short frames.
+	 *  - Enable CRC generation.
+	 *  Actual reconfiguration of MAC for resolved speed/duplex
+	 *  is followed after detection of link establishment.
+	 *  AR813x/AR815x always does checksum computation regardless
+	 *  of MAC_CFG_RXCSUM_ENB bit. Also the controller is known to
+	 *  have bug in protocol field in Rx return structure so
+	 *  these controllers can't handle fragmented frames. Disable
+	 *  Rx checksum offloading until there is a newer controller
+	 *  that has sane implementation.
+	 */
+	reg = MAC_CFG_TX_CRC_ENB | MAC_CFG_TX_AUTO_PAD | MAC_CFG_FULL_DUPLEX |
+	    ((MAC_CFG_PREAMBLE_DEFAULT << MAC_CFG_PREAMBLE_SHIFT) &
+	    MAC_CFG_PREAMBLE_MASK);
+	if ((ctlr->flags & alcfl_ar816x) != 0 ||
+	    ctlr->did == attansic_l1d ||
+	    ctlr->did == attansic_l1d_1 ||
+	    ctlr->did == attansic_l2c_2)
+		reg |= MAC_CFG_HASH_ALG_CRC32 | MAC_CFG_SPEED_MODE_SW;
+	if ((ctlr->flags & alcfl_fasteth) != 0)
+		reg |= MAC_CFG_SPEED_10_100;
+	else
+		reg |= MAC_CFG_SPEED_1000;
+	csr32w(ctlr, ALC_MAC_CFG, reg);
+
+	reg = csr32r(ctlr, ALC_MAC_CFG);
+	reg &= ~(MAC_CFG_ALLMULTI | MAC_CFG_BCAST | MAC_CFG_PROMISC);
+	reg |= MAC_CFG_BCAST;
+	csr32w(ctlr, ALC_MAC_CFG, reg);
+
+	reg = csr32r(ctlr, ALC_MAC_CFG);
+	reg &= ~MAC_CFG_VLAN_TAG_STRIP;
+	csr32w(ctlr, ALC_MAC_CFG, reg);
+
+	/* Acknowledge all pending interrupts and clear it. */
+	csr32w(ctlr, ALC_INTR_MASK, ALC_INTRS);
+	csr32w(ctlr, ALC_INTR_STATUS, 0xFFFFFFFF);
+	csr32w(ctlr, ALC_INTR_STATUS, 0);
+
+ out:
+	qunlock(&ctlr->alock);
+	return;
+ memerr:
+	qunlock(&ctlr->alock);
+	print("%s: can not allocate memory\n", ctlr->edev->name);
+	return;
+}
+static void
+interrupt(Ureg*, void* arg)
+{
+	Ctlr *ctlr;
+	Ether *edev;
+	uint status;
+	edev = arg;
+	ctlr = edev->ctlr;
+	ilock(&ctlr->imlock);
+	status = csr32r(ctlr, ALC_INTR_STATUS);
+	if ((status & ALC_INTRS) == 0)
+		goto out;
+	/* Disable interrupts. */
+	csr32w(ctlr, ALC_INTR_STATUS, INTR_DIS_INT);
+	status = csr32r(ctlr, ALC_INTR_STATUS);
+	if ((status & ALC_INTRS) == 0)
+		goto back;
+	/* Acknowledge and disable interrupts. */
+	csr32w(ctlr, ALC_INTR_STATUS, status | INTR_DIS_INT);
+	if (status & INTR_GPHY) {
+		mii_read(ctlr, ctlr->phy, 0x13); /* clean phy interrupts */
+		ctlr->lim = INTR_GPHY;
+		wakeup(&ctlr->lrendez);
+	}
+	if (status & INTR_RX_PKT) {
+		ctlr->rim = INTR_RX_PKT;
+		wakeup(&ctlr->rrendez);
+	}
+	if (status & (INTR_DMA_RD_TO_RST | INTR_DMA_WR_TO_RST |
+		      INTR_TXQ_TO_RST)) {
+		if (status & INTR_DMA_RD_TO_RST)
+			print("%s: DMA read error!\n",
+			       ctlr->edev->name);
+		if (status & INTR_DMA_WR_TO_RST)
+			print("%s: DMA write error!\n",
+			       ctlr->edev->name);
+		if (status & INTR_TXQ_TO_RST)
+			print("%s: TxQ reset!\n",
+			       ctlr->edev->name);
+	}
+
+ back:
+	csr32w(ctlr, ALC_INTR_STATUS, 0x7fffffff);
+ out:
+	iunlock(&ctlr->imlock);
+	alc_transmit(edev);
+}
+
+static char *stat_rx[] =  {
+	/* Rx stats. */
+	"rx_frames",
+	"rx_bcast_frames",
+	"rx_mcast_frames",
+	"rx_pause_frames",
+	"rx_control_frames",
+	"rx_crcerrs",
+	"rx_lenerrs",
+	"rx_bytes",
+	"rx_runts",
+	"rx_fragments",
+	"rx_pkts_64",
+	"rx_pkts_65_127",
+	"rx_pkts_128_255",
+	"rx_pkts_256_511",
+	"rx_pkts_512_1023",
+	"rx_pkts_1024_1518",
+	"rx_pkts_1519_max",
+	"rx_pkts_truncated",
+	"rx_fifo_oflows",
+	"rx_rrs_errs",
+	"rx_alignerrs",
+	"rx_bcast_bytes",
+	"rx_mcast_bytes",
+	"rx_pkts_filtered" };
+
+static char *stat_tx[] =  {
+	/* Tx stats. */
+	"tx_frames",
+	"tx_bcast_frames",
+	"tx_mcast_frames",
+	"tx_pause_frames",
+	"tx_excess_defer",
+	"tx_control_frames",
+	"tx_deferred",
+	"tx_bytes",
+	"tx_pkts_64",
+	"tx_pkts_65_127",
+	"tx_pkts_128_255",
+	"tx_pkts_256_511",
+	"tx_pkts_512_1023",
+	"tx_pkts_1024_1518",
+	"tx_pkts_1519_max",
+	"tx_single_colls",
+	"tx_multi_colls",
+	"tx_late_colls",
+	"tx_excess_colls",
+	"tx_underrun",
+	"tx_desc_underrun",
+	"tx_lenerrs",
+	"tx_pkts_truncated",
+	"tx_bcast_bytes",
+	"tx_mcast_bytes"
+};
+
+static long
+alc_ifstat(Ether *edev, void* a, long n, ulong offset)
+{
+	Ctlr *ctlr;
+	char *p;
+	int i, l, r;
+
+	p = smalloc(READSTR);
+	l = 0;
+	ctlr = edev->ctlr;
+	qlock(&ctlr->slock);
+	for(i = 0; i < sizeof(stat_rx) / sizeof(char*); i++) {
+		r = csr32r(ctlr, ALC_RX_MIB_BASE + i*4);
+		l += snprint(p+l, READSTR-l, "%s: %ud\n",
+			     stat_rx[i], r);
+		i++;
+	}
+	for(i = 0; i < sizeof(stat_tx) / sizeof(char*); i++) {
+		r = csr32r(ctlr, ALC_TX_MIB_BASE + i*4);
+		l += snprint(p+l, READSTR-l, "%s: %ud\n",
+			     stat_tx[i], r);
+		i++;
+	}
+	if(ctlr->mii != nil && ctlr->mii->curphy != nil){
+		l += snprint(p+l, READSTR-l, "phy:   ");
+		for(i = 0; i < NMiiPhyr; i++){
+			if(i && ((i & 0x07) == 0))
+				l += snprint(p+l, READSTR-l, "\n       ");
+			r = miimir(ctlr->mii, i);
+			l += snprint(p+l, READSTR-l, " %4.4uX", r);
+		}
+		snprint(p+l, READSTR-l, "\n");
+	}
+	n = readstr(offset, a, n, p);
+	free(p);
+	qunlock(&ctlr->slock);
+	return n;
+}
+
+static int
+alcpnp(Ether* edev)
+{
+	Ctlr *ctlr;
+
+	if(alcctlrhead == nil)
+		alcpci(edev);
+
+	/*
+	 * Any adapter matches if no edev->port is supplied,
+	 * otherwise the ports must match.
+	 */
+	for(ctlr = alcctlrhead; ctlr != nil; ctlr = ctlr->next){
+		if(ctlr->active)
+			continue;
+		if(edev->port == 0 || edev->port == ctlr->port){
+			ctlr->active = 1;
+			break;
+		}
+	}
+	if(ctlr == nil)
+		return -1;
+	edev->ctlr = ctlr;
+	edev->port = ctlr->port;
+	edev->irq = ctlr->pcidev->intl;
+	edev->tbdf = ctlr->pcidev->tbdf;
+	edev->mbps = 1000;
+	memmove(edev->ea, ctlr->ra, Eaddrlen);
+
+	/*
+	 * Linkage to the generic ethernet driver.
+	 */
+	edev->attach = alc_attach;
+	edev->transmit = alc_transmit;
+	edev->ifstat = alc_ifstat;
+
+	edev->arg = edev;
+	edev->promiscuous = alc_promisc;
+	// TODO edev->shutdown
+	// TODO edev->multicast
+
+	intrenable(edev->irq, interrupt, edev, edev->tbdf, edev->name);
+
+	return 0;
+}
+
+void
+etheralclink(void)
+{
+	addethercard("alc", alcpnp);
+}
diff -r 484d3f8e5978 sys/src/9/pc/etheralc.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/9/pc/etheralc.h	Wed Sep 30 19:54:09 2020 +0300
@@ -0,0 +1,1155 @@
+/* Taken from if_alcreg.h from OpenBSD */
+
+/*-
+ * Copyright (c) 2009, Pyun YongHyeon <yongari@FreeBSD.org>
+ * 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 unmodified, 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD: src/sys/dev/alc/if_alcreg.h,v 1.1 2009/06/10 02:07:58 yongari Exp $
+ */
+
+#define	ALC_PCIR_BAR			0x10
+
+#define	ATHEROS_AR8152_B_V10		0xC0
+#define	ATHEROS_AR8152_B_V11		0xC1
+
+/*
+ * Atheros AR816x/AR817x revisions
+ */
+#define	AR816X_REV_A0			0
+#define	AR816X_REV_A1			1
+#define	AR816X_REV_B0			2
+#define	AR816X_REV_C0			3
+
+#define	AR816X_REV_SHIFT		3
+#define	AR816X_REV(x)			((x) >> AR816X_REV_SHIFT)
+
+/* 0x0000 - 0x02FF : PCIe configuration space */
+
+#define	ALC_PEX_UNC_ERR_SEV		0x10C
+#define	PEX_UNC_ERR_SEV_TRN		0x00000001
+#define	PEX_UNC_ERR_SEV_DLP		0x00000010
+#define	PEX_UNC_ERR_SEV_PSN_TLP		0x00001000
+#define	PEX_UNC_ERR_SEV_FCP		0x00002000
+#define	PEX_UNC_ERR_SEV_CPL_TO		0x00004000
+#define	PEX_UNC_ERR_SEV_CA		0x00008000
+#define	PEX_UNC_ERR_SEV_UC		0x00010000
+#define	PEX_UNC_ERR_SEV_ROV		0x00020000
+#define	PEX_UNC_ERR_SEV_MLFP		0x00040000
+#define	PEX_UNC_ERR_SEV_ECRC		0x00080000
+#define	PEX_UNC_ERR_SEV_UR		0x00100000
+
+#define	ALC_EEPROM_LD			0x204	/* AR816x */
+#define	EEPROM_LD_START			0x00000001
+#define	EEPROM_LD_IDLE			0x00000010
+#define	EEPROM_LD_DONE			0x00000000
+#define	EEPROM_LD_PROGRESS		0x00000020
+#define	EEPROM_LD_EXIST			0x00000100
+#define	EEPROM_LD_EEPROM_EXIST		0x00000200
+#define	EEPROM_LD_FLASH_EXIST		0x00000400
+#define	EEPROM_LD_FLASH_END_ADDR_MASK	0x03FF0000
+#define	EEPROM_LD_FLASH_END_ADDR_SHIFT	16
+
+#define	ALC_TWSI_CFG			0x218
+#define	TWSI_CFG_SW_LD_START		0x00000800
+#define	TWSI_CFG_HW_LD_START		0x00001000
+#define	TWSI_CFG_LD_EXIST		0x00400000
+
+#define	ALC_SLD				0x218	/* AR816x */
+#define	SLD_START			0x00000800
+#define	SLD_PROGRESS			0x00001000
+#define	SLD_IDLE			0x00002000
+#define	SLD_SLVADDR_MASK		0x007F0000
+#define	SLD_EXIST			0x00800000
+#define	SLD_FREQ_MASK			0x03000000
+#define	SLD_FREQ_100K			0x00000000
+#define	SLD_FREQ_200K			0x01000000
+#define	SLD_FREQ_300K			0x02000000
+#define	SLD_FREQ_400K			0x03000000
+
+#define	PCIEM_LINK_CAP_ASPM		0x00000c00
+#define	PCIEM_LINK_CTL_RCB		0x0008
+#define	PCIEM_LINK_CTL_ASPMC_DIS	0x0000
+#define	PCIEM_LINK_CTL_ASPMC_L0S	0x0001
+#define	PCIEM_LINK_CTL_ASPMC_L1		0x0002
+#define	PCIEM_LINK_CTL_ASPMC		0x0003
+
+#define	ALC_PCIE_PHYMISC		0x1000
+#define	PCIE_PHYMISC_FORCE_RCV_DET	0x00000004
+
+#define	ALC_PCIE_PHYMISC2		0x1004
+#define	PCIE_PHYMISC2_SERDES_CDR_MASK	0x00030000
+#define	PCIE_PHYMISC2_SERDES_TH_MASK	0x000C0000
+#define	PCIE_PHYMISC2_SERDES_CDR_SHIFT	16
+#define	PCIE_PHYMISC2_SERDES_TH_SHIFT	18
+
+#define	ALC_PDLL_TRNS1			0x1104
+#define	PDLL_TRNS1_D3PLLOFF_ENB		0x00000800
+
+#define	ALC_TWSI_DEBUG			0x1108
+#define	TWSI_DEBUG_DEV_EXIST		0x20000000
+
+#define	ALC_EEPROM_CFG			0x12C0
+#define	EEPROM_CFG_DATA_HI_MASK		0x0000FFFF
+#define	EEPROM_CFG_ADDR_MASK		0x03FF0000
+#define	EEPROM_CFG_ACK			0x40000000
+#define	EEPROM_CFG_RW			0x80000000
+#define	EEPROM_CFG_DATA_HI_SHIFT	0
+#define	EEPROM_CFG_ADDR_SHIFT		16
+
+#define	ALC_EEPROM_DATA_LO		0x12C4
+
+#define	ALC_OPT_CFG			0x12F0
+#define	OPT_CFG_CLK_ENB			0x00000002
+
+#define	ALC_PM_CFG			0x12F8
+#define	PM_CFG_SERDES_ENB		0x00000001
+#define	PM_CFG_RBER_ENB			0x00000002
+#define	PM_CFG_CLK_REQ_ENB		0x00000004
+#define	PM_CFG_ASPM_L1_ENB		0x00000008
+#define	PM_CFG_SERDES_L1_ENB		0x00000010
+#define	PM_CFG_SERDES_PLL_L1_ENB	0x00000020
+#define	PM_CFG_SERDES_PD_EX_L1		0x00000040
+#define	PM_CFG_SERDES_BUDS_RX_L1_ENB	0x00000080
+#define	PM_CFG_L0S_ENTRY_TIMER_MASK	0x00000F00
+#define	PM_CFG_RX_L1_AFTER_L0S		0x00000800
+#define	PM_CFG_ASPM_L0S_ENB		0x00001000
+#define	PM_CFG_CLK_SWH_L1		0x00002000
+#define	PM_CFG_CLK_PWM_VER1_1		0x00004000
+#define	PM_CFG_PCIE_RECV		0x00008000
+#define	PM_CFG_L1_ENTRY_TIMER_MASK	0x000F0000
+#define	PM_CFG_L1_ENTRY_TIMER_816X_MASK	0x00070000
+#define	PM_CFG_TX_L1_AFTER_L0S		0x00080000
+#define	PM_CFG_PM_REQ_TIMER_MASK	0x00F00000
+#define	PM_CFG_LCKDET_TIMER_MASK	0x0F000000
+#define	PM_CFG_EN_BUFS_RX_L0S		0x10000000
+#define	PM_CFG_SA_DLY_ENB		0x20000000
+#define	PM_CFG_MAC_ASPM_CHK		0x40000000
+#define	PM_CFG_HOTRST			0x80000000
+#define	PM_CFG_L0S_ENTRY_TIMER_SHIFT	8
+#define	PM_CFG_L1_ENTRY_TIMER_SHIFT	16
+#define	PM_CFG_PM_REQ_TIMER_SHIFT	20
+#define	PM_CFG_LCKDET_TIMER_SHIFT	24
+
+#define	PM_CFG_L0S_ENTRY_TIMER_DEFAULT	6
+#define	PM_CFG_L1_ENTRY_TIMER_DEFAULT	1
+#define	PM_CFG_L1_ENTRY_TIMER_816X_DEFAULT	4
+#define	PM_CFG_LCKDET_TIMER_DEFAULT	12
+#define	PM_CFG_PM_REQ_TIMER_DEFAULT	12
+#define	PM_CFG_PM_REQ_TIMER_816X_DEFAULT	15
+
+#define	ALC_LTSSM_ID_CFG		0x12FC
+#define	LTSSM_ID_WRO_ENB		0x00001000
+
+#define	ALC_MASTER_CFG			0x1400
+#define	MASTER_RESET			0x00000001
+#define	MASTER_TEST_MODE_MASK		0x0000000C
+#define	MASTER_BERT_START		0x00000010
+#define	MASTER_OOB_DIS_OFF		0x00000040
+#define	MASTER_SA_TIMER_ENB		0x00000080
+#define	MASTER_MTIMER_ENB		0x00000100
+#define	MASTER_MANUAL_INTR_ENB		0x00000200
+#define	MASTER_IM_TX_TIMER_ENB		0x00000400
+#define	MASTER_IM_RX_TIMER_ENB		0x00000800
+#define	MASTER_CLK_SEL_DIS		0x00001000
+#define	MASTER_CLK_SWH_MODE		0x00002000
+#define	MASTER_INTR_RD_CLR		0x00004000
+#define	MASTER_CHIP_REV_MASK		0x00FF0000
+#define	MASTER_CHIP_ID_MASK		0x7F000000
+#define	MASTER_OTP_SEL			0x80000000
+#define	MASTER_TEST_MODE_SHIFT		2
+#define	MASTER_CHIP_REV_SHIFT		16
+#define	MASTER_CHIP_ID_SHIFT		24
+
+/* Number of ticks per usec for AR813x/AR815x. */
+#define	ALC_TICK_USECS			2
+#define	ALC_USECS(x)			((x) / ALC_TICK_USECS)
+
+#define	ALC_MANUAL_TIMER		0x1404
+
+#define	ALC_IM_TIMER			0x1408
+#define	IM_TIMER_TX_MASK		0x0000FFFF
+#define	IM_TIMER_RX_MASK		0xFFFF0000
+#define	IM_TIMER_TX_SHIFT		0
+#define	IM_TIMER_RX_SHIFT		16
+#define	ALC_IM_TIMER_MIN		0
+#define	ALC_IM_TIMER_MAX		130000	/* 130ms */
+/*
+ * 100us will ensure alc(4) wouldn't generate more than 10000 Rx
+ * interrupts in a second.
+ */
+#define	ALC_IM_RX_TIMER_DEFAULT		100	/* 100us */
+/*
+ * alc(4) does not rely on Tx completion interrupts, so set it
+ * somewhat large value to reduce Tx completion interrupts.
+ */
+#define	ALC_IM_TX_TIMER_DEFAULT		1000	/* 1ms */
+
+#define	ALC_GPHY_CFG			0x140C	/* 16 bits, 32 bits on AR816x */
+
+#define	GPHY_CFG_EXT_RESET		0x0001
+#define	GPHY_CFG_RTL_MODE		0x0002
+#define	GPHY_CFG_LED_MODE		0x0004
+#define	GPHY_CFG_ANEG_NOW		0x0008
+#define	GPHY_CFG_RECV_ANEG		0x0010
+#define	GPHY_CFG_GATE_25M_ENB		0x0020
+#define	GPHY_CFG_LPW_EXIT		0x0040
+#define	GPHY_CFG_PHY_IDDQ		0x0080
+#define	GPHY_CFG_PHY_IDDQ_DIS		0x0100
+#define	GPHY_CFG_PCLK_SEL_DIS		0x0200
+#define	GPHY_CFG_HIB_EN			0x0400
+#define	GPHY_CFG_HIB_PULSE		0x0800
+#define	GPHY_CFG_SEL_ANA_RESET		0x1000
+#define	GPHY_CFG_PHY_PLL_ON		0x2000
+#define	GPHY_CFG_PWDOWN_HW		0x4000
+#define	GPHY_CFG_PHY_PLL_BYPASS		0x8000
+#define	GPHY_CFG_100AB_ENB		0x00020000
+
+#define	ALC_IDLE_STATUS			0x1410
+#define	IDLE_STATUS_RXMAC		0x00000001
+#define	IDLE_STATUS_TXMAC		0x00000002
+#define	IDLE_STATUS_RXQ			0x00000004
+#define	IDLE_STATUS_TXQ			0x00000008
+#define	IDLE_STATUS_DMARD		0x00000010
+#define	IDLE_STATUS_DMAWR		0x00000020
+#define	IDLE_STATUS_SMB			0x00000040
+#define	IDLE_STATUS_CMB			0x00000080
+
+#define	ALC_MDIO			0x1414
+#define	MDIO_DATA_MASK			0x0000FFFF
+#define	MDIO_REG_ADDR_MASK		0x001F0000
+#define	MDIO_OP_READ			0x00200000
+#define	MDIO_OP_WRITE			0x00000000
+#define	MDIO_SUP_PREAMBLE		0x00400000
+#define	MDIO_OP_EXECUTE			0x00800000
+#define	MDIO_CLK_25_4			0x00000000
+#define	MDIO_CLK_25_6			0x02000000
+#define	MDIO_CLK_25_8			0x03000000
+#define	MDIO_CLK_25_10			0x04000000
+#define	MDIO_CLK_25_14			0x05000000
+#define	MDIO_CLK_25_20			0x06000000
+#define	MDIO_CLK_25_128			0x07000000
+#define	MDIO_OP_BUSY			0x08000000
+#define	MDIO_AP_ENB			0x10000000
+#define	MDIO_MODE_EXT			0x40000000
+#define	MDIO_DATA_SHIFT			0
+#define	MDIO_REG_ADDR_SHIFT		16
+
+#define	MDIO_REG_ADDR(x)	\
+	(((x) << MDIO_REG_ADDR_SHIFT) & MDIO_REG_ADDR_MASK)
+/* Default PHY address. */
+#define	ALC_PHY_ADDR			0
+
+#define	ALC_PHY_STATUS			0x1418
+#define	PHY_STATUS_RECV_ENB		0x00000001
+#define	PHY_STATUS_GENERAL_MASK		0x0000FFFF
+#define	PHY_STATUS_OE_PWSP_MASK		0x07FF0000
+#define	PHY_STATUS_LPW_STATE		0x80000000
+#define	PHY_STATIS_OE_PWSP_SHIFT	16
+
+/* Packet memory BIST. */
+#define	ALC_BIST0			0x141C
+#define	BIST0_ENB			0x00000001
+#define	BIST0_SRAM_FAIL			0x00000002
+#define	BIST0_FUSE_FLAG			0x00000004
+
+/* PCIe retry buffer BIST. */
+#define	ALC_BIST1			0x1420
+#define	BIST1_ENB			0x00000001
+#define	BIST1_SRAM_FAIL			0x00000002
+#define	BIST1_FUSE_FLAG			0x00000004
+
+#define	ALC_SERDES_LOCK			0x1424
+#define	SERDES_LOCK_DET			0x00000001
+#define	SERDES_LOCK_DET_ENB		0x00000002
+#define	SERDES_MAC_CLK_SLOWDOWN		0x00020000
+#define	SERDES_PHY_CLK_SLOWDOWN		0x00040000
+
+#define	ALC_LPI_CTL			0x1440
+#define	LPI_CTL_ENB			0x00000001
+
+#define	ALC_EXT_MDIO			0x1448
+#define	EXT_MDIO_REG_MASK		0x0000FFFF
+#define	EXT_MDIO_DEVADDR_MASK		0x001F0000
+#define	EXT_MDIO_REG_SHIFT		0
+#define	EXT_MDIO_DEVADDR_SHIFT		16
+
+#define	EXT_MDIO_REG(x)		\
+	(((x) << EXT_MDIO_REG_SHIFT) & EXT_MDIO_REG_MASK)
+#define	EXT_MDIO_DEVADDR(x)	\
+	(((x) << EXT_MDIO_DEVADDR_SHIFT) & EXT_MDIO_DEVADDR_MASK)
+
+#define	ALC_IDLE_DECISN_TIMER		0x1474
+#define	IDLE_DECISN_TIMER_DEFAULT_1MS	0x400
+
+#define	ALC_MAC_CFG			0x1480
+#define	MAC_CFG_TX_ENB			0x00000001
+#define	MAC_CFG_RX_ENB			0x00000002
+#define	MAC_CFG_TX_FC			0x00000004
+#define	MAC_CFG_RX_FC			0x00000008
+#define	MAC_CFG_LOOP			0x00000010
+#define	MAC_CFG_FULL_DUPLEX		0x00000020
+#define	MAC_CFG_TX_CRC_ENB		0x00000040
+#define	MAC_CFG_TX_AUTO_PAD		0x00000080
+#define	MAC_CFG_TX_LENCHK		0x00000100
+#define	MAC_CFG_RX_JUMBO_ENB		0x00000200
+#define	MAC_CFG_PREAMBLE_MASK		0x00003C00
+#define	MAC_CFG_VLAN_TAG_STRIP		0x00004000
+#define	MAC_CFG_PROMISC			0x00008000
+#define	MAC_CFG_TX_PAUSE		0x00010000
+#define	MAC_CFG_SCNT			0x00020000
+#define	MAC_CFG_SYNC_RST_TX		0x00040000
+#define	MAC_CFG_SIM_RST_TX		0x00080000
+#define	MAC_CFG_SPEED_MASK		0x00300000
+#define	MAC_CFG_SPEED_10_100		0x00100000
+#define	MAC_CFG_SPEED_1000		0x00200000
+#define	MAC_CFG_DBG_TX_BACKOFF		0x00400000
+#define	MAC_CFG_TX_JUMBO_ENB		0x00800000
+#define	MAC_CFG_RXCSUM_ENB		0x01000000
+#define	MAC_CFG_ALLMULTI		0x02000000
+#define	MAC_CFG_BCAST			0x04000000
+#define	MAC_CFG_DBG			0x08000000
+#define	MAC_CFG_SINGLE_PAUSE_ENB	0x10000000
+#define	MAC_CFG_HASH_ALG_CRC32		0x20000000
+#define	MAC_CFG_SPEED_MODE_SW		0x40000000
+#define	MAC_CFG_FAST_PAUSE		0x80000000
+#define	MAC_CFG_PREAMBLE_SHIFT		10
+#define	MAC_CFG_PREAMBLE_DEFAULT	7
+
+#define	ALC_IPG_IFG_CFG			0x1484
+#define	IPG_IFG_IPGT_MASK		0x0000007F
+#define	IPG_IFG_MIFG_MASK		0x0000FF00
+#define	IPG_IFG_IPG1_MASK		0x007F0000
+#define	IPG_IFG_IPG2_MASK		0x7F000000
+#define	IPG_IFG_IPGT_SHIFT		0
+#define	IPG_IFG_IPGT_DEFAULT		0x60
+#define	IPG_IFG_MIFG_SHIFT		8
+#define	IPG_IFG_MIFG_DEFAULT		0x50
+#define	IPG_IFG_IPG1_SHIFT		16
+#define	IPG_IFG_IPG1_DEFAULT		0x40
+#define	IPG_IFG_IPG2_SHIFT		24
+#define	IPG_IFG_IPG2_DEFAULT		0x60
+
+/* Station address. */
+#define	ALC_PAR0			0x1488
+#define	ALC_PAR1			0x148C
+
+/* 64bit multicast hash register. */
+#define	ALC_MAR0			0x1490
+#define	ALC_MAR1			0x1494
+
+/* half-duplex parameter configuration. */
+#define	ALC_HDPX_CFG			0x1498
+#define	HDPX_CFG_LCOL_MASK		0x000003FF
+#define	HDPX_CFG_RETRY_MASK		0x0000F000
+#define	HDPX_CFG_EXC_DEF_EN		0x00010000
+#define	HDPX_CFG_NO_BACK_C		0x00020000
+#define	HDPX_CFG_NO_BACK_P		0x00040000
+#define	HDPX_CFG_ABEBE			0x00080000
+#define	HDPX_CFG_ABEBT_MASK		0x00F00000
+#define	HDPX_CFG_JAMIPG_MASK		0x0F000000
+#define	HDPX_CFG_LCOL_SHIFT		0
+#define	HDPX_CFG_LCOL_DEFAULT		0x37
+#define	HDPX_CFG_RETRY_SHIFT		12
+#define	HDPX_CFG_RETRY_DEFAULT		0x0F
+#define	HDPX_CFG_ABEBT_SHIFT		20
+#define	HDPX_CFG_ABEBT_DEFAULT		0x0A
+#define	HDPX_CFG_JAMIPG_SHIFT		24
+#define	HDPX_CFG_JAMIPG_DEFAULT		0x07
+
+#define	ALC_FRAME_SIZE			0x149C
+
+#define	ALC_WOL_CFG			0x14A0
+#define	WOL_CFG_PATTERN			0x00000001
+#define	WOL_CFG_PATTERN_ENB		0x00000002
+#define	WOL_CFG_MAGIC			0x00000004
+#define	WOL_CFG_MAGIC_ENB		0x00000008
+#define	WOL_CFG_LINK_CHG		0x00000010
+#define	WOL_CFG_LINK_CHG_ENB		0x00000020
+#define	WOL_CFG_PATTERN_DET		0x00000100
+#define	WOL_CFG_MAGIC_DET		0x00000200
+#define	WOL_CFG_LINK_CHG_DET		0x00000400
+#define	WOL_CFG_CLK_SWITCH_ENB		0x00008000
+#define	WOL_CFG_PATTERN0		0x00010000
+#define	WOL_CFG_PATTERN1		0x00020000
+#define	WOL_CFG_PATTERN2		0x00040000
+#define	WOL_CFG_PATTERN3		0x00080000
+#define	WOL_CFG_PATTERN4		0x00100000
+#define	WOL_CFG_PATTERN5		0x00200000
+#define	WOL_CFG_PATTERN6		0x00400000
+
+/* WOL pattern length. */
+#define	ALC_PATTERN_CFG0		0x14A4
+#define	PATTERN_CFG_0_LEN_MASK		0x0000007F
+#define	PATTERN_CFG_1_LEN_MASK		0x00007F00
+#define	PATTERN_CFG_2_LEN_MASK		0x007F0000
+#define	PATTERN_CFG_3_LEN_MASK		0x7F000000
+
+#define	ALC_PATTERN_CFG1		0x14A8
+#define	PATTERN_CFG_4_LEN_MASK		0x0000007F
+#define	PATTERN_CFG_5_LEN_MASK		0x00007F00
+#define	PATTERN_CFG_6_LEN_MASK		0x007F0000
+
+/* RSS */
+#define	ALC_RSS_KEY0			0x14B0
+
+#define	ALC_RSS_KEY1			0x14B4
+
+#define	ALC_RSS_KEY2			0x14B8
+
+#define	ALC_RSS_KEY3			0x14BC
+
+#define	ALC_RSS_KEY4			0x14C0
+
+#define	ALC_RSS_KEY5			0x14C4
+
+#define	ALC_RSS_KEY6			0x14C8
+
+#define	ALC_RSS_KEY7			0x14CC
+
+#define	ALC_RSS_KEY8			0x14D0
+
+#define	ALC_RSS_KEY9			0x14D4
+
+#define	ALC_RSS_IDT_TABLE0		0x14E0
+
+#define	ALC_TD_PRI2_HEAD_ADDR_LO	0x14E0	/* AR816x */
+
+#define	ALC_RSS_IDT_TABLE1		0x14E4
+
+#define	ALC_TD_PRI3_HEAD_ADDR_LO	0x14E4	/* AR816x */
+
+#define	ALC_RSS_IDT_TABLE2		0x14E8
+
+#define	ALC_RSS_IDT_TABLE3		0x14EC
+
+#define	ALC_RSS_IDT_TABLE4		0x14F0
+
+#define	ALC_RSS_IDT_TABLE5		0x14F4
+
+#define	ALC_RSS_IDT_TABLE6		0x14F8
+
+#define	ALC_RSS_IDT_TABLE7		0x14FC
+
+#define	ALC_SRAM_RD0_ADDR		0x1500
+
+#define	ALC_SRAM_RD1_ADDR		0x1504
+
+#define	ALC_SRAM_RD2_ADDR		0x1508
+
+#define	ALC_SRAM_RD3_ADDR		0x150C
+
+#define	RD_HEAD_ADDR_MASK		0x000003FF
+#define	RD_TAIL_ADDR_MASK		0x03FF0000
+#define	RD_HEAD_ADDR_SHIFT		0
+#define	RD_TAIL_ADDR_SHIFT		16
+
+#define	ALC_RD_NIC_LEN0			0x1510	/* 8 bytes unit */
+#define	RD_NIC_LEN_MASK			0x000003FF
+
+#define	ALC_RD_NIC_LEN1			0x1514
+
+#define	ALC_SRAM_TD_ADDR		0x1518
+#define	TD_HEAD_ADDR_MASK		0x000003FF
+#define	TD_TAIL_ADDR_MASK		0x03FF0000
+#define	TD_HEAD_ADDR_SHIFT		0
+#define	TD_TAIL_ADDR_SHIFT		16
+
+#define	ALC_SRAM_TD_LEN			0x151C	/* 8 bytes unit */
+#define	SRAM_TD_LEN_MASK		0x000003FF
+
+#define	ALC_SRAM_RX_FIFO_ADDR		0x1520
+
+#define	ALC_SRAM_RX_FIFO_LEN		0x1524
+#define	SRAM_RX_FIFO_LEN_MASK		0x00000FFF
+#define	SRAM_RX_FIFO_LEN_SHIFT		0
+
+#define	ALC_SRAM_TX_FIFO_ADDR		0x1528
+
+#define	ALC_SRAM_TX_FIFO_LEN		0x152C
+
+#define	ALC_SRAM_TCPH_ADDR		0x1530
+#define	SRAM_TCPH_ADDR_MASK		0x00000FFF
+#define	SRAM_PATH_ADDR_MASK		0x0FFF0000
+#define	SRAM_TCPH_ADDR_SHIFT		0
+#define	SRAM_PKTH_ADDR_SHIFT		16
+
+#define	ALC_DMA_BLOCK			0x1534
+#define	DMA_BLOCK_LOAD			0x00000001
+
+#define	ALC_RX_BASE_ADDR_HI		0x1540
+
+#define	ALC_TX_BASE_ADDR_HI		0x1544
+
+#define	ALC_SMB_BASE_ADDR_HI		0x1548
+
+#define	ALC_SMB_BASE_ADDR_LO		0x154C
+
+#define	ALC_RD0_HEAD_ADDR_LO		0x1550
+
+#define	ALC_RD1_HEAD_ADDR_LO		0x1554
+
+#define	ALC_RD2_HEAD_ADDR_LO		0x1558
+
+#define	ALC_RD3_HEAD_ADDR_LO		0x155C
+
+#define	ALC_RD_RING_CNT			0x1560
+#define	RD_RING_CNT_MASK		0x00000FFF
+#define	RD_RING_CNT_SHIFT		0
+
+#define	ALC_RX_BUF_SIZE			0x1564
+#define	RX_BUF_SIZE_MASK		0x0000FFFF
+/*
+ * If larger buffer size than 1536 is specified the controller
+ * will be locked up. This is hardware limitation.
+ */
+#define	RX_BUF_SIZE_MAX			1536
+
+#define	ALC_RRD0_HEAD_ADDR_LO		0x1568
+
+#define	ALC_RRD1_HEAD_ADDR_LO		0x156C
+
+#define	ALC_RRD2_HEAD_ADDR_LO		0x1570
+
+#define	ALC_RRD3_HEAD_ADDR_LO		0x1574
+
+#define	ALC_RRD_RING_CNT		0x1578
+#define	RRD_RING_CNT_MASK		0x00000FFF
+#define	RRD_RING_CNT_SHIFT		0
+
+#define	ALC_TDH_HEAD_ADDR_LO		0x157C
+
+#define	ALC_TD_PRI1_HEAD_ADDR_LO	0x157C	/* AR816x */
+
+#define	ALC_TDL_HEAD_ADDR_LO		0x1580
+
+#define	ALC_TD_PRI0_HEAD_ADDR_LO	0x1580	/* AR816x */
+
+#define	ALC_TD_RING_CNT			0x1584
+#define	TD_RING_CNT_MASK		0x0000FFFF
+#define	TD_RING_CNT_SHIFT		0
+
+#define	ALC_CMB_BASE_ADDR_LO		0x1588
+
+#define	ALC_TXQ_CFG			0x1590
+#define	TXQ_CFG_TD_BURST_MASK		0x0000000F
+#define	TXQ_CFG_IP_OPTION_ENB		0x00000010
+#define	TXQ_CFG_ENB			0x00000020
+#define	TXQ_CFG_ENHANCED_MODE		0x00000040
+#define	TXQ_CFG_8023_ENB		0x00000080
+#define	TXQ_CFG_TX_FIFO_BURST_MASK	0xFFFF0000
+#define	TXQ_CFG_TD_BURST_SHIFT		0
+#define	TXQ_CFG_TD_BURST_DEFAULT	5
+#define	TXQ_CFG_TX_FIFO_BURST_SHIFT	16
+
+#define	ALC_TSO_OFFLOAD_THRESH		0x1594	/* 8 bytes unit */
+#define	TSO_OFFLOAD_THRESH_MASK		0x000007FF
+#define	TSO_OFFLOAD_ERRLGPKT_DROP_ENB	0x00000800
+#define	TSO_OFFLOAD_THRESH_SHIFT	0
+#define	TSO_OFFLOAD_THRESH_UNIT		8
+#define	TSO_OFFLOAD_THRESH_UNIT_SHIFT	3
+
+#define	ALC_TXF_WATER_MARK		0x1598	/* 8 bytes unit */
+#define	TXF_WATER_MARK_HI_MASK		0x00000FFF
+#define	TXF_WATER_MARK_LO_MASK		0x0FFF0000
+#define	TXF_WATER_MARK_BURST_ENB	0x80000000
+#define	TXF_WATER_MARK_LO_SHIFT		0
+#define	TXF_WATER_MARK_HI_SHIFT		16
+
+#define	ALC_THROUGHPUT_MON		0x159C
+#define	THROUGHPUT_MON_RATE_MASK	0x00000003
+#define	THROUGHPUT_MON_ENB		0x00000080
+#define	THROUGHPUT_MON_RATE_SHIFT	0
+
+#define	ALC_RXQ_CFG			0x15A0
+#define	RXQ_CFG_ASPM_THROUGHPUT_LIMIT_MASK	0x00000003
+#define	RXQ_CFG_ASPM_THROUGHPUT_LIMIT_NONE	0x00000000
+#define	RXQ_CFG_ASPM_THROUGHPUT_LIMIT_1M	0x00000001
+#define	RXQ_CFG_ASPM_THROUGHPUT_LIMIT_10M	0x00000002
+#define	RXQ_CFG_ASPM_THROUGHPUT_LIMIT_100M	0x00000003
+#define	RXQ_CFG_QUEUE1_ENB		0x00000010
+#define	RXQ_CFG_QUEUE2_ENB		0x00000020
+#define	RXQ_CFG_QUEUE3_ENB		0x00000040
+#define	RXQ_CFG_IPV6_CSUM_ENB		0x00000080
+#define	RXQ_CFG_RSS_HASH_TBL_LEN_MASK	0x0000FF00
+#define	RXQ_CFG_RSS_HASH_IPV4		0x00010000
+#define	RXQ_CFG_RSS_HASH_IPV4_TCP	0x00020000
+#define	RXQ_CFG_RSS_HASH_IPV6		0x00040000
+#define	RXQ_CFG_RSS_HASH_IPV6_TCP	0x00080000
+#define	RXQ_CFG_RD_BURST_MASK		0x03F00000
+#define	RXQ_CFG_RSS_MODE_DIS		0x00000000
+#define	RXQ_CFG_RSS_MODE_SQSINT		0x04000000
+#define	RXQ_CFG_RSS_MODE_MQUESINT	0x08000000
+#define	RXQ_CFG_RSS_MODE_MQUEMINT	0x0C000000
+#define	RXQ_CFG_NIP_QUEUE_SEL_TBL	0x10000000
+#define	RXQ_CFG_RSS_HASH_ENB		0x20000000
+#define	RXQ_CFG_CUT_THROUGH_ENB		0x40000000
+#define	RXQ_CFG_QUEUE0_ENB		0x80000000
+#define	RXQ_CFG_RSS_HASH_TBL_LEN_SHIFT	8
+#define	RXQ_CFG_RD_BURST_DEFAULT	8
+#define	RXQ_CFG_RD_BURST_SHIFT		20
+#define	RXQ_CFG_ENB					\
+	(RXQ_CFG_QUEUE0_ENB | RXQ_CFG_QUEUE1_ENB |	\
+	 RXQ_CFG_QUEUE2_ENB | RXQ_CFG_QUEUE3_ENB)
+
+/* AR816x specific bits */
+#define	RXQ_CFG_816X_RSS_HASH_IPV4	0x00000004
+#define	RXQ_CFG_816X_RSS_HASH_IPV4_TCP	0x00000008
+#define	RXQ_CFG_816X_RSS_HASH_IPV6	0x00000010
+#define	RXQ_CFG_816X_RSS_HASH_IPV6_TCP	0x00000020
+#define	RXQ_CFG_816X_RSS_HASH_MASK	0x0000003C
+#define	RXQ_CFG_816X_IPV6_PARSE_ENB	0x00000080
+#define	RXQ_CFG_816X_IDT_TBL_SIZE_MASK	0x0001FF00
+#define	RXQ_CFG_816X_IDT_TBL_SIZE_SHIFT	8
+#define	RXQ_CFG_816X_IDT_TBL_SIZE_DEFAULT	0x100
+
+#define	ALC_RX_RD_FREE_THRESH		0x15A4	/* 8 bytes unit. */
+#define	RX_RD_FREE_THRESH_HI_MASK	0x0000003F
+#define	RX_RD_FREE_THRESH_LO_MASK	0x00000FC0
+#define	RX_RD_FREE_THRESH_HI_SHIFT	0
+#define	RX_RD_FREE_THRESH_LO_SHIFT	6
+#define	RX_RD_FREE_THRESH_HI_DEFAULT	16
+#define	RX_RD_FREE_THRESH_LO_DEFAULT	8
+
+#define	ALC_RX_FIFO_PAUSE_THRESH	0x15A8
+#define	RX_FIFO_PAUSE_THRESH_LO_MASK	0x00000FFF
+#define	RX_FIFO_PAUSE_THRESH_HI_MASK	0x0FFF0000
+#define	RX_FIFO_PAUSE_THRESH_LO_SHIFT	0
+#define	RX_FIFO_PAUSE_THRESH_HI_SHIFT	16
+
+/*
+ * Size = tx-packet(1522)  IPG(12) + SOF(8) + 64(Pause) + IPG(12) + SOF(8) +
+ * rx-packet(1522) + delay-of-link(64) = 3212.
+ */
+#define	RX_FIFO_PAUSE_816X_RSVD		3212
+
+#define	ALC_RD_DMA_CFG			0x15AC
+#define	RD_DMA_CFG_THRESH_MASK		0x00000FFF	/* 8 bytes unit */
+#define	RD_DMA_CFG_TIMER_MASK		0xFFFF0000
+#define	RD_DMA_CFG_THRESH_SHIFT		0
+#define	RD_DMA_CFG_TIMER_SHIFT		16
+#define	RD_DMA_CFG_THRESH_DEFAULT	0x100
+#define	RD_DMA_CFG_TIMER_DEFAULT	0
+#define	RD_DMA_CFG_TICK_USECS		8
+#define	ALC_RD_DMA_CFG_USECS(x)		((x) / RD_DMA_CFG_TICK_USECS)
+
+#define	ALC_RSS_HASH_VALUE		0x15B0
+
+#define	ALC_RSS_HASH_FLAG		0x15B4
+
+#define	ALC_RSS_CPU			0x15B8
+
+#define	ALC_DMA_CFG			0x15C0
+#define	DMA_CFG_IN_ORDER		0x00000001
+#define	DMA_CFG_ENH_ORDER		0x00000002
+#define	DMA_CFG_OUT_ORDER		0x00000004
+#define	DMA_CFG_RCB_64			0x00000000
+#define	DMA_CFG_RCB_128			0x00000008
+#define	DMA_CFG_RD_BURST_128		0x00000000
+#define	DMA_CFG_RD_BURST_256		0x00000010
+#define	DMA_CFG_RD_BURST_512		0x00000020
+#define	DMA_CFG_RD_BURST_1024		0x00000030
+#define	DMA_CFG_RD_BURST_2048		0x00000040
+#define	DMA_CFG_RD_BURST_4096		0x00000050
+#define	DMA_CFG_WR_BURST_128		0x00000000
+#define	DMA_CFG_WR_BURST_256		0x00000080
+#define	DMA_CFG_WR_BURST_512		0x00000100
+#define	DMA_CFG_WR_BURST_1024		0x00000180
+#define	DMA_CFG_WR_BURST_2048		0x00000200
+#define	DMA_CFG_WR_BURST_4096		0x00000280
+#define	DMA_CFG_RD_REQ_PRI		0x00000400
+#define	DMA_CFG_RD_DELAY_CNT_MASK	0x0000F800
+#define	DMA_CFG_WR_DELAY_CNT_MASK	0x000F0000
+#define	DMA_CFG_CMB_ENB			0x00100000
+#define	DMA_CFG_SMB_ENB			0x00200000
+#define	DMA_CFG_CMB_NOW			0x00400000
+#define	DMA_CFG_SMB_DIS			0x01000000
+#define	DMA_CFG_RD_CHNL_SEL_MASK	0x0C000000
+#define	DMA_CFG_RD_CHNL_SEL_1		0x00000000
+#define	DMA_CFG_RD_CHNL_SEL_2		0x04000000
+#define	DMA_CFG_RD_CHNL_SEL_3		0x08000000
+#define	DMA_CFG_RD_CHNL_SEL_4		0x0C000000
+#define	DMA_CFG_WSRAM_RDCTL		0x10000000
+#define	DMA_CFG_RD_PEND_CLR		0x20000000
+#define	DMA_CFG_WR_PEND_CLR		0x40000000
+#define	DMA_CFG_SMB_NOW			0x80000000
+#define	DMA_CFG_RD_BURST_MASK		0x07
+#define	DMA_CFG_RD_BURST_SHIFT		4
+#define	DMA_CFG_WR_BURST_MASK		0x07
+#define	DMA_CFG_WR_BURST_SHIFT		7
+#define	DMA_CFG_RD_DELAY_CNT_SHIFT	11
+#define	DMA_CFG_WR_DELAY_CNT_SHIFT	16
+#define	DMA_CFG_RD_DELAY_CNT_DEFAULT	15
+#define	DMA_CFG_WR_DELAY_CNT_DEFAULT	4
+
+#define	ALC_SMB_STAT_TIMER		0x15C4
+#define	SMB_STAT_TIMER_MASK		0x00FFFFFF
+#define	SMB_STAT_TIMER_SHIFT		0
+
+#define	ALC_CMB_TD_THRESH		0x15C8
+#define	CMB_TD_THRESH_MASK		0x0000FFFF
+#define	CMB_TD_THRESH_SHIFT		0
+
+#define	ALC_CMB_TX_TIMER		0x15CC
+#define	CMB_TX_TIMER_MASK		0x0000FFFF
+#define	CMB_TX_TIMER_SHIFT		0
+
+#define	ALC_MSI_MAP_TBL1		0x15D0
+
+#define	ALC_MSI_ID_MAP			0x15D4
+
+#define	ALC_MSI_MAP_TBL2		0x15D8
+
+#define	ALC_MBOX_RD0_PROD_IDX		0x15E0
+
+#define	ALC_MBOX_RD1_PROD_IDX		0x15E4
+
+#define	ALC_MBOX_RD2_PROD_IDX		0x15E8
+
+#define	ALC_MBOX_RD3_PROD_IDX		0x15EC
+
+#define	ALC_MBOX_RD_PROD_MASK		0x0000FFFF
+#define	MBOX_RD_PROD_SHIFT		0
+
+#define	ALC_MBOX_TD_PROD_IDX		0x15F0
+#define	MBOX_TD_PROD_HI_IDX_MASK	0x0000FFFF
+#define	MBOX_TD_PROD_LO_IDX_MASK	0xFFFF0000
+#define	MBOX_TD_PROD_HI_IDX_SHIFT	0
+#define	MBOX_TD_PROD_LO_IDX_SHIFT	16
+
+#define	ALC_MBOX_TD_PRI1_PROD_IDX	0x15F0	/* 16 bits AR816x */
+#define	ALC_MBOX_TD_PRI0_PROD_IDX	0x15F2	/* 16 bits AR816x */
+#define	ALC_MBOX_TD_CONS_IDX		0x15F4
+#define	MBOX_TD_CONS_HI_IDX_MASK	0x0000FFFF
+#define	MBOX_TD_CONS_LO_IDX_MASK	0xFFFF0000
+#define	MBOX_TD_CONS_HI_IDX_SHIFT	0
+#define	MBOX_TD_CONS_LO_IDX_SHIFT	16
+
+#define	ALC_MBOX_TD_PRI1_CONS_IDX	0x15F4	/* 16 bits AR816x */
+#define	ALC_MBOX_TD_PRI0_CONS_IDX	0x15F6	/* 16 bits AR816x */
+
+#define	ALC_MBOX_RD01_CONS_IDX		0x15F8
+#define	MBOX_RD0_CONS_IDX_MASK		0x0000FFFF
+#define	MBOX_RD1_CONS_IDX_MASK		0xFFFF0000
+#define	MBOX_RD0_CONS_IDX_SHIFT		0
+#define	MBOX_RD1_CONS_IDX_SHIFT		16
+
+#define	ALC_MBOX_RD23_CONS_IDX		0x15FC
+#define	MBOX_RD2_CONS_IDX_MASK		0x0000FFFF
+#define	MBOX_RD3_CONS_IDX_MASK		0xFFFF0000
+#define	MBOX_RD2_CONS_IDX_SHIFT		0
+#define	MBOX_RD3_CONS_IDX_SHIFT		16
+
+#define	ALC_INTR_STATUS			0x1600
+#define	INTR_SMB			0x00000001
+#define	INTR_TIMER			0x00000002
+#define	INTR_MANUAL_TIMER		0x00000004
+#define	INTR_RX_FIFO_OFLOW		0x00000008
+#define	INTR_RD0_UNDERRUN		0x00000010
+#define	INTR_RD1_UNDERRUN		0x00000020
+#define	INTR_RD2_UNDERRUN		0x00000040
+#define	INTR_RD3_UNDERRUN		0x00000080
+#define	INTR_TX_FIFO_UNDERRUN		0x00000100
+#define	INTR_DMA_RD_TO_RST		0x00000200
+#define	INTR_DMA_WR_TO_RST		0x00000400
+#define	INTR_TX_CREDIT			0x00000800
+#define	INTR_GPHY			0x00001000
+#define	INTR_GPHY_LOW_PW		0x00002000
+#define	INTR_TXQ_TO_RST			0x00004000
+#define	INTR_TX_PKT0			0x00008000
+#define	INTR_RX_PKT0			0x00010000
+#define	INTR_RX_PKT1			0x00020000
+#define	INTR_RX_PKT2			0x00040000
+#define	INTR_RX_PKT3			0x00080000
+#define	INTR_MAC_RX			0x00100000
+#define	INTR_MAC_TX			0x00200000
+#define	INTR_UNDERRUN			0x00400000
+#define	INTR_FRAME_ERROR		0x00800000
+#define	INTR_FRAME_OK			0x01000000
+#define	INTR_CSUM_ERROR			0x02000000
+#define	INTR_PHY_LINK_DOWN		0x04000000
+#define	INTR_DIS_INT			0x80000000
+
+/* INTR status for AR816x/AR817x  4 TX queues, 8 RX queues */
+#define	INTR_TX_PKT1			0x00000020
+#define	INTR_TX_PKT2			0x00000040
+#define	INTR_TX_PKT3			0x00000080
+#define	INTR_RX_PKT4			0x08000000
+#define	INTR_RX_PKT5			0x10000000
+#define	INTR_RX_PKT6			0x20000000
+#define	INTR_RX_PKT7			0x40000000
+
+/* Interrupt Mask Register */
+#define	ALC_INTR_MASK			0x1604
+
+#define	INTR_TX_PKT			INTR_TX_PKT0
+#define	INTR_RX_PKT			INTR_RX_PKT0
+#define	INTR_RD_UNDERRUN		INTR_RD0_UNDERRUN
+
+#define	ALC_INTRS					\
+	(INTR_DMA_RD_TO_RST | INTR_DMA_WR_TO_RST |	\
+	INTR_TXQ_TO_RST	| INTR_RX_PKT | INTR_TX_PKT |	\
+	INTR_RX_FIFO_OFLOW | INTR_RD_UNDERRUN |		\
+	INTR_TX_FIFO_UNDERRUN | INTR_GPHY)
+#define	ALC_INTR_RETRIG_TIMER		0x1608
+#define	INTR_RETRIG_TIMER_MASK		0x0000FFFF
+#define	INTR_RETRIG_TIMER_SHIFT		0
+
+#define	ALC_HDS_CFG			0x160C
+#define	HDS_CFG_ENB			0x00000001
+#define	HDS_CFG_BACKFILLSIZE_MASK	0x000FFF00
+#define	HDS_CFG_MAX_HDRSIZE_MASK	0xFFF00000
+#define	HDS_CFG_BACKFILLSIZE_SHIFT	8
+#define	HDS_CFG_MAX_HDRSIZE_SHIFT	20
+
+#define	ALC_MBOX_TD_PRI3_PROD_IDX	0x1618	/* 16 bits AR816x */
+#define	ALC_MBOX_TD_PRI2_PROD_IDX	0x161A	/* 16 bits AR816x */
+#define	ALC_MBOX_TD_PRI3_CONS_IDX	0x161C	/* 16 bits AR816x */
+#define	ALC_MBOX_TD_PRI2_CONS_IDX	0x161E	/* 16 bits AR816x */
+
+/* AR813x/AR815x registers for MAC statistics */
+#define	ALC_RX_MIB_BASE			0x1700
+
+#define	ALC_TX_MIB_BASE			0x1760
+
+#define	ALC_DRV				0x1804	/* AR816x */
+#define	DRV_ASPM_SPD10LMT_1M		0x00000000
+#define	DRV_ASPM_SPD10LMT_10M		0x00000001
+#define	DRV_ASPM_SPD10LMT_100M		0x00000002
+#define	DRV_ASPM_SPD10LMT_NO		0x00000003
+#define	DRV_ASPM_SPD10LMT_MASK		0x00000003
+#define	DRV_ASPM_SPD100LMT_1M		0x00000000
+#define	DRV_ASPM_SPD100LMT_10M		0x00000004
+#define	DRV_ASPM_SPD100LMT_100M		0x00000008
+#define	DRV_ASPM_SPD100LMT_NO		0x0000000C
+#define	DRV_ASPM_SPD100LMT_MASK		0x0000000C
+#define	DRV_ASPM_SPD1000LMT_100M	0x00000000
+#define	DRV_ASPM_SPD1000LMT_NO		0x00000010
+#define	DRV_ASPM_SPD1000LMT_1M		0x00000020
+#define	DRV_ASPM_SPD1000LMT_10M		0x00000030
+#define	DRV_ASPM_SPD1000LMT_MASK	0x00000000
+#define	DRV_WOLCAP_BIOS_EN		0x00000100
+#define	DRV_WOLMAGIC_EN			0x00000200
+#define	DRV_WOLLINKUP_EN		0x00000400
+#define	DRV_WOLPATTERN_EN		0x00000800
+#define	DRV_AZ_EN			0x00001000
+#define	DRV_WOLS5_BIOS_EN		0x00010000
+#define	DRV_WOLS5_EN			0x00020000
+#define	DRV_DISABLE			0x00040000
+#define	DRV_PHY_MASK			0x1FE00000
+#define	DRV_PHY_EEE			0x00200000
+#define	DRV_PHY_APAUSE			0x00400000
+#define	DRV_PHY_PAUSE			0x00800000
+#define	DRV_PHY_DUPLEX			0x01000000
+#define	DRV_PHY_10			0x02000000
+#define	DRV_PHY_100			0x04000000
+#define	DRV_PHY_1000			0x08000000
+#define	DRV_PHY_AUTO			0x10000000
+#define	DRV_PHY_SHIFT			21
+
+#define	ALC_CLK_GATING_CFG		0x1814
+#define	CLK_GATING_DMAW_ENB		0x0001
+#define	CLK_GATING_DMAR_ENB		0x0002
+#define	CLK_GATING_TXQ_ENB		0x0004
+#define	CLK_GATING_RXQ_ENB		0x0008
+#define	CLK_GATING_TXMAC_ENB		0x0010
+#define	CLK_GATING_RXMAC_ENB		0x0020
+
+#define	ALC_DEBUG_DATA0			0x1900
+
+#define	ALC_DEBUG_DATA1			0x1904
+
+#define	ALC_MSI_RETRANS_TIMER		0x1920
+#define	MSI_RETRANS_TIMER_MASK		0x0000FFFF
+#define	MSI_RETRANS_MASK_SEL_STD	0x00000000
+#define	MSI_RETRANS_MASK_SEL_LINE	0x00010000
+#define	MSI_RETRANS_TIMER_SHIFT		0
+
+#define	ALC_WRR				0x1938
+#define	WRR_PRI0_MASK			0x0000001F
+#define	WRR_PRI1_MASK			0x00001F00
+#define	WRR_PRI2_MASK			0x001F0000
+#define	WRR_PRI3_MASK			0x1F000000
+#define	WRR_PRI_RESTRICT_MASK		0x60000000
+#define	WRR_PRI_RESTRICT_ALL		0x00000000
+#define	WRR_PRI_RESTRICT_HI		0x20000000
+#define	WRR_PRI_RESTRICT_HI2		0x40000000
+#define	WRR_PRI_RESTRICT_NONE		0x60000000
+#define	WRR_PRI0_SHIFT			0
+#define	WRR_PRI1_SHIFT			8
+#define	WRR_PRI2_SHIFT			16
+#define	WRR_PRI3_SHIFT			24
+#define	WRR_PRI_DEFAULT			4
+#define	WRR_PRI_RESTRICT_SHIFT		29
+
+#define	ALC_HQTD_CFG			0x193C
+#define	HQTD_CFG_Q1_BURST_MASK		0x0000000F
+#define	HQTD_CFG_Q2_BURST_MASK		0x000000F0
+#define	HQTD_CFG_Q3_BURST_MASK		0x00000F00
+#define	HQTD_CFG_BURST_ENB		0x80000000
+#define	HQTD_CFG_Q1_BURST_SHIFT		0
+#define	HQTD_CFG_Q2_BURST_SHIFT		4
+#define	HQTD_CFG_Q3_BURST_SHIFT		8
+
+#define	ALC_MISC			0x19C0
+#define	MISC_INTNLOSC_OPEN		0x00000008
+#define	MISC_ISO_ENB			0x00001000
+#define	MISC_PSW_OCP_MASK		0x00E00000
+#define	MISC_PSW_OCP_SHIFT		21
+#define	MISC_PSW_OCP_DEFAULT		7
+
+#define	ALC_MISC2			0x19C8
+#define	MISC2_CALB_START		0x00000001
+
+#define	ALC_MISC3			0x19CC
+#define	MISC3_25M_NOTO_INTNL		0x00000001
+#define	MISC3_25M_BY_SW			0x00000002
+
+#define	ALC_MII_DBG_ADDR		0x1D
+#define	ALC_MII_DBG_DATA		0x1E
+
+#define	MII_ANA_CFG0			0x00
+#define	ANA_RESTART_CAL			0x0001
+#define	ANA_MANUL_SWICH_ON_MASK		0x001E
+#define	ANA_MAN_ENABLE			0x0020
+#define	ANA_SEL_HSP			0x0040
+#define	ANA_EN_HB			0x0080
+#define	ANA_EN_HBIAS			0x0100
+#define	ANA_OEN_125M			0x0200
+#define	ANA_EN_LCKDT			0x0400
+#define	ANA_LCKDT_PHY			0x0800
+#define	ANA_AFE_MODE			0x1000
+#define	ANA_VCO_SLOW			0x2000
+#define	ANA_VCO_FAST			0x4000
+#define	ANA_SEL_CLK125M_DSP		0x8000
+#define	ANA_MANUL_SWICH_ON_SHIFT	1
+
+#define	MII_DBG_ANACTL			0x00
+#define	DBG_ANACTL_DEFAULT		0x02EF
+
+#define	MII_ANA_CFG4			0x04
+#define	ANA_IECHO_ADJ_MASK		0x0F
+#define	ANA_IECHO_ADJ_3_MASK		0x000F
+#define	ANA_IECHO_ADJ_2_MASK		0x00F0
+#define	ANA_IECHO_ADJ_1_MASK		0x0F00
+#define	ANA_IECHO_ADJ_0_MASK		0xF000
+#define	ANA_IECHO_ADJ_3_SHIFT		0
+#define	ANA_IECHO_ADJ_2_SHIFT		4
+#define	ANA_IECHO_ADJ_1_SHIFT		8
+#define	ANA_IECHO_ADJ_0_SHIFT		12
+
+#define	MII_DBG_SYSMODCTL		0x04
+#define	DBG_SYSMODCTL_DEFAULT		0xBB8B
+
+#define	MII_ANA_CFG5			0x05
+#define	ANA_SERDES_CDR_BW_MASK		0x0003
+#define	ANA_MS_PAD_DBG			0x0004
+#define	ANA_SPEEDUP_DBG			0x0008
+#define	ANA_SERDES_TH_LOS_MASK		0x0030
+#define	ANA_SERDES_EN_DEEM		0x0040
+#define	ANA_SERDES_TXELECIDLE		0x0080
+#define	ANA_SERDES_BEACON		0x0100
+#define	ANA_SERDES_HALFTXDR		0x0200
+#define	ANA_SERDES_SEL_HSP		0x0400
+#define	ANA_SERDES_EN_PLL		0x0800
+#define	ANA_SERDES_EN			0x1000
+#define	ANA_SERDES_EN_LCKDT		0x2000
+#define	ANA_SERDES_CDR_BW_SHIFT		0
+#define	ANA_SERDES_TH_LOS_SHIFT		4
+
+#define	MII_DBG_SRDSYSMOD		0x05
+#define	DBG_SRDSYSMOD_DEFAULT		0x2C46
+
+#define	MII_ANA_CFG11			0x0B
+#define	ANA_PS_HIB_EN			0x8000
+
+#define	MII_DBG_HIBNEG			0x0B
+#define	DBG_HIBNEG_HIB_PULSE		0x1000
+#define	DBG_HIBNEG_PSHIB_EN		0x8000
+#define	DBG_HIBNEG_DEFAULT		0xBC40
+
+#define	MII_ANA_CFG18			0x12
+#define	ANA_TEST_MODE_10BT_01MASK	0x0003
+#define	ANA_LOOP_SEL_10BT		0x0004
+#define	ANA_RGMII_MODE_SW		0x0008
+#define	ANA_EN_LONGECABLE		0x0010
+#define	ANA_TEST_MODE_10BT_2		0x0020
+#define	ANA_EN_10BT_IDLE		0x0400
+#define	ANA_EN_MASK_TB			0x0800
+#define	ANA_TRIGGER_SEL_TIMER_MASK	0x3000
+#define	ANA_INTERVAL_SEL_TIMER_MASK	0xC000
+#define	ANA_TEST_MODE_10BT_01SHIFT	0
+#define	ANA_TRIGGER_SEL_TIMER_SHIFT	12
+#define	ANA_INTERVAL_SEL_TIMER_SHIFT	14
+
+#define	MII_DBG_TST10BTCFG		0x12
+#define	DBG_TST10BTCFG_DEFAULT		0x4C04
+
+#define	MII_DBG_AZ_ANADECT		0x15
+#define	DBG_AZ_ANADECT_DEFAULT		0x3220
+#define	DBG_AZ_ANADECT_LONG		0x3210
+
+#define	MII_DBG_MSE16DB			0x18
+#define	DBG_MSE16DB_UP			0x05EA
+#define	DBG_MSE16DB_DOWN		0x02EA
+
+#define	MII_DBG_MSE20DB			0x1C
+#define	DBG_MSE20DB_TH_MASK		0x01FC
+#define	DBG_MSE20DB_TH_DEFAULT		0x2E
+#define	DBG_MSE20DB_TH_HI		0x54
+#define	DBG_MSE20DB_TH_SHIFT		2
+
+#define	MII_DBG_AGC			0x23
+#define	DBG_AGC_2_VGA_MASK		0x3F00
+#define	DBG_AGC_2_VGA_SHIFT		8
+#define	DBG_AGC_LONG1G_LIMT		40
+#define	DBG_AGC_LONG100M_LIMT		44
+
+#define	MII_ANA_CFG41			0x29
+#define	ANA_TOP_PS_EN			0x8000
+
+#define	MII_DBG_LEGCYPS			0x29
+#define	DBG_LEGCYPS_ENB			0x8000
+#define	DBG_LEGCYPS_DEFAULT		0x129D
+
+#define	MII_ANA_CFG54			0x36
+#define	ANA_LONG_CABLE_TH_100_MASK	0x003F
+#define	ANA_DESERVED			0x0040
+#define	ANA_EN_LIT_CH			0x0080
+#define	ANA_SHORT_CABLE_TH_100_MASK	0x3F00
+#define	ANA_BP_BAD_LINK_ACCUM		0x4000
+#define	ANA_BP_SMALL_BW			0x8000
+#define	ANA_LONG_CABLE_TH_100_SHIFT	0
+#define	ANA_SHORT_CABLE_TH_100_SHIFT	8
+
+#define	MII_DBG_TST100BTCFG		0x36
+#define	DBG_TST100BTCFG_DEFAULT		0xE12C
+
+#define	MII_DBG_GREENCFG		0x3B
+#define	DBG_GREENCFG_DEFAULT		0x7078
+
+#define	MII_DBG_GREENCFG2		0x3D
+#define	DBG_GREENCFG2_GATE_DFSE_EN	0x0080
+#define	DBG_GREENCFG2_BP_GREEN		0x8000
+
+/* Device addr 3 */
+#define	MII_EXT_PCS			3
+
+#define	MII_EXT_CLDCTL3			0x8003
+#define	EXT_CLDCTL3_BP_CABLE1TH_DET_GT	0x8000
+
+#define	MII_EXT_CLDCTL5			0x8005
+#define	EXT_CLDCTL5_BP_VD_HLFBIAS	0x4000
+
+#define	MII_EXT_CLDCTL6			0x8006
+#define	EXT_CLDCTL6_CAB_LEN_MASK	0x00FF
+#define	EXT_CLDCTL6_CAB_LEN_SHIFT	0
+#define	EXT_CLDCTL6_CAB_LEN_SHORT1G	116
+#define	EXT_CLDCTL6_CAB_LEN_SHORT100M	152
+
+#define	MII_EXT_VDRVBIAS		0x8062
+#define	EXT_VDRVBIAS_DEFAULT		3
+
+/* Device addr 7 */
+#define	MII_EXT_ANEG			7
+
+#define	MII_EXT_ANEG_LOCAL_EEEADV	0x3C
+#define	ANEG_LOCA_EEEADV_100BT		0x0002
+#define	ANEG_LOCA_EEEADV_1000BT		0x0004
+
+#define	MII_EXT_ANEG_AFE		0x801A
+#define	ANEG_AFEE_10BT_100M_TH		0x0040
+
+#define	MII_EXT_ANEG_S3DIG10		0x8023
+#define	ANEG_S3DIG10_SL			0x0001
+#define	ANEG_S3DIG10_DEFAULT		0
+
+#define	MII_EXT_ANEG_NLP78		0x8027
+#define	ANEG_NLP78_120M_DEFAULT		0x8A05
+
+#define	RRD_CSUM_MASK			0x0000FFFF
+#define	RRD_RD_CNT_MASK			0x000F0000
+#define	RRD_RD_IDX_MASK			0xFFF00000
+#define	RRD_CSUM_SHIFT			0
+#define	RRD_RD_CNT_SHIFT		16
+#define	RRD_RD_IDX_SHIFT		20
+#define	RRD_CSUM(x)			\
+	(((x) & RRD_CSUM_MASK) >> RRD_CSUM_SHIFT)
+#define	RRD_RD_CNT(x)			\
+	(((x) & RRD_RD_CNT_MASK) >> RRD_RD_CNT_SHIFT)
+#define	RRD_RD_IDX(x)			\
+	(((x) & RRD_RD_IDX_MASK) >> RRD_RD_IDX_SHIFT)
+#define	RRD_VLAN_MASK			0x0000FFFF
+#define	RRD_HEAD_LEN_MASK		0x00FF0000
+#define	RRD_HDS_MASK			0x03000000
+#define	RRD_HDS_NONE			0x00000000
+#define	RRD_HDS_HEAD			0x01000000
+#define	RRD_HDS_DATA			0x02000000
+#define	RRD_CPU_MASK			0x0C000000
+#define	RRD_HASH_FLAG_MASK		0xF0000000
+#define	RRD_VLAN_SHIFT			0
+#define	RRD_HEAD_LEN_SHIFT		16
+#define	RRD_HDS_SHIFT			24
+#define	RRD_CPU_SHIFT			26
+#define	RRD_HASH_FLAG_SHIFT		28
+#define	RRD_VLAN(x)			\
+	(((x) & RRD_VLAN_MASK) >> RRD_VLAN_SHIFT)
+#define	RRD_HEAD_LEN(x)			\
+	(((x) & RRD_HEAD_LEN_MASK) >> RRD_HEAD_LEN_SHIFT)
+#define	RRD_CPU(x)			\
+	(((x) & RRD_CPU_MASK) >> RRD_CPU_SHIFT)
+#define	RRD_LEN_MASK			0x00003FFF
+#define	RRD_LEN_SHIFT			0
+#define	RRD_TCP_UDPCSUM_NOK		0x00004000
+#define	RRD_IPCSUM_NOK			0x00008000
+#define	RRD_VLAN_TAG			0x00010000
+#define	RRD_PROTO_MASK			0x000E0000
+#define	RRD_PROTO_IPV4			0x00020000
+#define	RRD_PROTO_IPV6			0x000C0000
+#define	RRD_ERR_SUM			0x00100000
+#define	RRD_ERR_CRC			0x00200000
+#define	RRD_ERR_ALIGN			0x00400000
+#define	RRD_ERR_TRUNC			0x00800000
+#define	RRD_ERR_RUNT			0x01000000
+#define	RRD_ERR_ICMP			0x02000000
+#define	RRD_BCAST			0x04000000
+#define	RRD_MCAST			0x08000000
+#define	RRD_SNAP_LLC			0x10000000
+#define	RRD_ETHER			0x00000000
+#define	RRD_FIFO_FULL			0x20000000
+#define	RRD_ERR_LENGTH			0x40000000
+#define	RRD_VALID			0x80000000
+#define	RRD_BYTES(x)			\
+	(((x) & RRD_LEN_MASK) >> RRD_LEN_SHIFT)
+#define	RRD_IPV4(x)			\
+	(((x) & RRD_PROTO_MASK) == RRD_PROTO_IPV4)
+
+#define	ALC_TX_TIMEOUT		5
+#define	ALC_RESET_TIMEOUT	100
+#define	ALC_TIMEOUT		1000
+#define	ALC_PHY_TIMEOUT		1000
+
+#define	MASTER_WAKEN_25M	0x00000020
+#define	ALC_FLAG_MSI		0x0004
+#define	ALC_FLAG_MSIX		0x0008
diff -r 484d3f8e5978 sys/src/9/pc/mkfile
--- a/sys/src/9/pc/mkfile	Tue Sep 29 07:28:47 2020 -0700
+++ b/sys/src/9/pc/mkfile	Wed Sep 30 19:54:09 2020 +0300
@@ -127,6 +127,7 @@
 ether8169.$O:			../port/ethermii.h
 etherdp83820.$O:		../port/ethermii.h
 etherigbe.$O:			../port/ethermii.h
+etheralc.$O:			../port/ethermii.h
 ethervgbe.$O:			../port/ethermii.h
 ethervt6102.$O:			../port/ethermii.h
 ethervt6105m.$O:		../port/ethermii.h
diff -r 484d3f8e5978 sys/src/9/pc/pc
--- a/sys/src/9/pc/pc	Tue Sep 29 07:28:47 2020 -0700
+++ b/sys/src/9/pc/pc	Wed Sep 30 19:54:09 2020 +0300
@@ -72,6 +72,7 @@
 	ethervgbe	pci ethermii
 	ethervt6102	pci ethermii
 	ethervt6105m	pci ethermii
+	etheralc	pci ethermii
 	ethersink
 	ethersmc	pci devi82365 cis
 	etheryuk	pci
diff -r 484d3f8e5978 sys/src/9/pc64/mkfile
--- a/sys/src/9/pc64/mkfile	Tue Sep 29 07:28:47 2020 -0700
+++ b/sys/src/9/pc64/mkfile	Wed Sep 30 19:54:09 2020 +0300
@@ -131,6 +131,7 @@
 ether8169.$O:			../port/ethermii.h
 etherdp83820.$O:		../port/ethermii.h
 etherigbe.$O:			../port/ethermii.h
+etheralc.$O:			../port/ethermii.h
 ethervgbe.$O:			../port/ethermii.h
 ethervt6102.$O:			../port/ethermii.h
 ethervt6105m.$O:		../port/ethermii.h
diff -r 484d3f8e5978 sys/src/9/pc64/pc64
--- a/sys/src/9/pc64/pc64	Tue Sep 29 07:28:47 2020 -0700
+++ b/sys/src/9/pc64/pc64	Wed Sep 30 19:54:09 2020 +0300
@@ -67,6 +67,7 @@
 #	etherelnk3	pci
 #	etherga620	pci
 	etherigbe	pci ethermii
+	etheralc	pci ethermii
 #	ethervgbe	pci ethermii
 #	ethervt6102	pci ethermii
 #	ethervt6105m	pci ethermii

             reply	other threads:[~2020-10-05  8:24 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-10-05  8:24 Peter Kosyh [this message]
2020-10-06  6:16 ` [9front] " cinap_lenrek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87lfgl13o1.fsf@factor-ts.ru \
    --to=p.kosyh@gmail.com \
    --cc=9front@9front.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).