From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-lj1-f194.google.com ([209.85.208.194]) by ewsd; Mon Oct 5 04:24:23 -0400 2020 Received: by mail-lj1-f194.google.com with SMTP id n25so6596495ljj.4 for <9front@9front.org>; Mon, 05 Oct 2020 01:24:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:user-agent:mime-version; bh=jD58KEWSk14FS2sFV2UMGG+GM1UwhNqo0daUXwiblBU=; b=ouXxqCjtayEh6kvQcyR9iyCFh1rnt69vYU0KNKYrglUfvx7ekTw5tz4/w5hjyilETQ GYcA7DTo91S+wy+UYuka32jRZOadCVCb7/p997KCYHTsWW4sotjSFHPtLkhRZU1mGkLf Fdb091/v/gZj4ghMwTs2WGIrWX9HCv7KWWFmus2Y4lrO9Fg226gxQB7BQwMr/i57DJYu YTV744ex6f6gy0qWKCAxyus9DfPK/PFp2dJMxM1YZ8h/V/XynsALtawqtxTSwL50MPwo c/O8CoKW12d9GWSKwSD651CY+E9DJ/XKf2+BaQ0LYbMdDbKufC2OO0SLJFz2Eq3QxwEF /Rew== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:user-agent :mime-version; bh=jD58KEWSk14FS2sFV2UMGG+GM1UwhNqo0daUXwiblBU=; b=Xy+NqPwGJdn44ABtyCmcMepsF8C6Bd32QUBYdvYBYcA3p+OEUp/Ylz7Vk2UsLhcOiU Rx2ZG+1y6KzyiMG6XeCHSridU1VW652qtOuhgXh5oWTpfFP4Q/48d67hDWmC93jJC5Ub 0opZpRH0iPBfmJNpzA4SXE11XxaaeoKsPYz9iltuP7uG+U1R1wmE0rSVIK3UQ8qWYIjv ScCSZpIWM5L+smFD7uL/vGFLXP8wEGQ5RbDWcUMgRdvfrPGNor3zH/+4vfdYI7JYXv4k +pskmBWguW1fKut4vsbDBdQ3DYKyAnZ+J0drIJKL6IOJwyNJEDtb6+DWYSx1lKi08kyy D+Jw== X-Gm-Message-State: AOAM531aPuFErrtmk2PcsZnEYWZfIfdueSi+v3rxRhq3PRYeFtxQk9m2 zagsLQuR/vs3pWaW2IaeIQhF6+bc6kU= X-Google-Smtp-Source: ABdhPJyTPVdecMXzBqa8XGSCBVHG/eTAh/iHKqYnt01o/AEfWbVrC6NYh7eiqnLU2X4i89RCA2OMMg== X-Received: by 2002:a2e:9992:: with SMTP id w18mr4454754lji.301.1601886257411; Mon, 05 Oct 2020 01:24:17 -0700 (PDT) Return-Path: Received: from localhost ([95.165.9.116]) by smtp.gmail.com with ESMTPSA id v16sm2446033ljc.84.2020.10.05.01.24.14 for <9front@9front.org> (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 05 Oct 2020 01:24:15 -0700 (PDT) From: Peter Kosyh To: 9front@9front.org Subject: [PATCH] alc ethernet driver port Date: Mon, 05 Oct 2020 11:24:14 +0300 Message-ID: <87lfgl13o1.fsf@factor-ts.ru> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.1 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" List-ID: <9front.9front.org> List-Help: X-Glyph: ➈ X-Bullshit: open component out-scaling controller --=-=-= Content-Type: text/plain 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. --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=etheralc.patch 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 + * 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; irb[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; itb[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 + * 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 --=-=-=--