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
next 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).