Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/pci catch up with FreeBSD driver, adds support for A...
details: https://anonhg.NetBSD.org/src/rev/507b09221e0f
branches: trunk
changeset: 762555:507b09221e0f
user: jmcneill <jmcneill%NetBSD.org@localhost>
date: Wed Feb 23 02:25:04 2011 +0000
description:
catch up with FreeBSD driver, adds support for AR815x chips
diffstat:
sys/dev/pci/if_alc.c | 421 ++++++++++++++++++++++++++++++++++++++---------
sys/dev/pci/if_alcreg.h | 62 +++++-
2 files changed, 389 insertions(+), 94 deletions(-)
diffs (truncated from 833 to 300 lines):
diff -r a8b597c07411 -r 507b09221e0f sys/dev/pci/if_alc.c
--- a/sys/dev/pci/if_alc.c Wed Feb 23 01:23:03 2011 +0000
+++ b/sys/dev/pci/if_alc.c Wed Feb 23 02:25:04 2011 +0000
@@ -26,7 +26,7 @@
* SUCH DAMAGE.
*/
-/* Driver for Atheros AR8131/AR8132 PCIe Ethernet. */
+/* Driver for Atheros AR813x/AR815x PCIe Ethernet. */
#ifdef _KERNEL_OPT
#include "vlan.h"
@@ -79,6 +79,25 @@
#include <dev/pci/if_alcreg.h>
+/*
+ * Devices supported by this driver.
+ */
+static struct alc_ident alc_ident_table[] = {
+ { PCI_VENDOR_ATTANSIC, PCI_PRODUCT_ATTANSIC_AR8131, 9 * 1024,
+ "Atheros AR8131 PCIe Gigabit Ethernet" },
+ { PCI_VENDOR_ATTANSIC, PCI_PRODUCT_ATTANSIC_AR8132, 9 * 1024,
+ "Atheros AR8132 PCIe Fast Ethernet" },
+ { PCI_VENDOR_ATTANSIC, PCI_PRODUCT_ATTANSIC_AR8151, 6 * 1024,
+ "Atheros AR8151 v1.0 PCIe Gigabit Ethernet" },
+ { PCI_VENDOR_ATTANSIC, PCI_PRODUCT_ATTANSIC_AR8151_V2, 6 * 1024,
+ "Atheros AR8151 v2.0 PCIe Gigabit Ethernet" },
+ { PCI_VENDOR_ATTANSIC, PCI_PRODUCT_ATTANSIC_AR8152_B, 6 * 1024,
+ "Atheros AR8152 v1.1 PCIe Fast Ethernet" },
+ { PCI_VENDOR_ATTANSIC, PCI_PRODUCT_ATTANSIC_AR8152_B2, 6 * 1024,
+ "Atheros AR8152 v2.0 PCIe Fast Ethernet" },
+ { 0, 0, 0, NULL },
+};
+
static int alc_match(device_t, cfdata_t, void *);
static void alc_attach(device_t, device_t, void *);
static int alc_detach(device_t, int);
@@ -90,11 +109,13 @@
static int alc_mediachange(struct ifnet *);
static void alc_mediastatus(struct ifnet *, struct ifmediareq *);
-static void alc_aspm(struct alc_softc *);
+static void alc_aspm(struct alc_softc *, int);
static void alc_disable_l0s_l1(struct alc_softc *);
static int alc_dma_alloc(struct alc_softc *);
static void alc_dma_free(struct alc_softc *);
static int alc_encap(struct alc_softc *, struct mbuf **);
+static struct alc_ident *
+ alc_find_ident(struct pci_attach_args *);
static void alc_get_macaddr(struct alc_softc *);
static void alc_init_cmb(struct alc_softc *);
static void alc_init_rr_ring(struct alc_softc *);
@@ -228,8 +249,8 @@
reg = CSR_READ_4(sc, ALC_MAC_CFG);
reg |= MAC_CFG_TX_ENB | MAC_CFG_RX_ENB;
CSR_WRITE_4(sc, ALC_MAC_CFG, reg);
+ alc_aspm(sc, IFM_SUBTYPE(mii->mii_media_active));
}
- alc_aspm(sc);
}
static void
@@ -261,44 +282,81 @@
return (error);
}
+static struct alc_ident *
+alc_find_ident(struct pci_attach_args *pa)
+{
+ struct alc_ident *ident;
+ uint16_t vendor, devid;
+
+ vendor = PCI_VENDOR(pa->pa_id);
+ devid = PCI_PRODUCT(pa->pa_id);
+ for (ident = alc_ident_table; ident->name != NULL; ident++) {
+ if (vendor == ident->vendorid && devid == ident->deviceid)
+ return (ident);
+ }
+
+ return (NULL);
+}
+
static int
alc_match(device_t dev, cfdata_t match, void *aux)
{
struct pci_attach_args *pa = aux;
- if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_ATTANSIC)
- return 0;
-
- switch (PCI_PRODUCT(pa->pa_id)) {
- case PCI_PRODUCT_ATTANSIC_AR8131:
- case PCI_PRODUCT_ATTANSIC_AR8132:
- case PCI_PRODUCT_ATTANSIC_AR8152_B2:
- break;
- default:
- return 0;
- }
-
- return 1;
+ return alc_find_ident(pa) != NULL;
}
static void
alc_get_macaddr(struct alc_softc *sc)
{
uint32_t ea[2], opt;
- int i;
+ uint16_t val;
+ int eeprom, i;
+ eeprom = 0;
opt = CSR_READ_4(sc, ALC_OPT_CFG);
- if ((CSR_READ_4(sc, ALC_TWSI_DEBUG) & TWSI_DEBUG_DEV_EXIST) != 0) {
+ if ((CSR_READ_4(sc, ALC_MASTER_CFG) & MASTER_OTP_SEL) != 0 &&
+ (CSR_READ_4(sc, ALC_TWSI_DEBUG) & TWSI_DEBUG_DEV_EXIST) != 0) {
/*
* EEPROM found, let TWSI reload EEPROM configuration.
* This will set ethernet address of controller.
*/
- if ((opt & OPT_CFG_CLK_ENB) == 0) {
- opt |= OPT_CFG_CLK_ENB;
- CSR_WRITE_4(sc, ALC_OPT_CFG, opt);
- CSR_READ_4(sc, ALC_OPT_CFG);
- DELAY(1000);
+ eeprom++;
+ switch (sc->alc_ident->deviceid) {
+ case PCI_PRODUCT_ATTANSIC_AR8131:
+ case PCI_PRODUCT_ATTANSIC_AR8132:
+ if ((opt & OPT_CFG_CLK_ENB) == 0) {
+ opt |= OPT_CFG_CLK_ENB;
+ CSR_WRITE_4(sc, ALC_OPT_CFG, opt);
+ CSR_READ_4(sc, ALC_OPT_CFG);
+ DELAY(1000);
+ }
+ break;
+ case PCI_PRODUCT_ATTANSIC_AR8151:
+ case PCI_PRODUCT_ATTANSIC_AR8151_V2:
+ case PCI_PRODUCT_ATTANSIC_AR8152_B:
+ case PCI_PRODUCT_ATTANSIC_AR8152_B2:
+ alc_miibus_writereg(sc->sc_dev, sc->alc_phyaddr,
+ ALC_MII_DBG_ADDR, 0x00);
+ val = alc_miibus_readreg(sc->sc_dev, sc->alc_phyaddr,
+ ALC_MII_DBG_DATA);
+ alc_miibus_writereg(sc->sc_dev, sc->alc_phyaddr,
+ ALC_MII_DBG_DATA, val & 0xFF7F);
+ alc_miibus_writereg(sc->sc_dev, sc->alc_phyaddr,
+ ALC_MII_DBG_ADDR, 0x3B);
+ val = alc_miibus_readreg(sc->sc_dev, sc->alc_phyaddr,
+ ALC_MII_DBG_DATA);
+ alc_miibus_writereg(sc->sc_dev, sc->alc_phyaddr,
+ ALC_MII_DBG_DATA, val | 0x0008);
+ DELAY(20);
+ break;
}
+
+ CSR_WRITE_4(sc, ALC_LTSSM_ID_CFG,
+ CSR_READ_4(sc, ALC_LTSSM_ID_CFG) & ~LTSSM_ID_WRO_ENB);
+ CSR_WRITE_4(sc, ALC_WOL_CFG, 0);
+ CSR_READ_4(sc, ALC_WOL_CFG);
+
CSR_WRITE_4(sc, ALC_TWSI_CFG, CSR_READ_4(sc, ALC_TWSI_CFG) |
TWSI_CFG_SW_LD_START);
for (i = 100; i > 0; i--) {
@@ -314,11 +372,36 @@
if (alcdebug)
printf("%s: EEPROM not found!\n", device_xname(sc->sc_dev));
}
- if ((opt & OPT_CFG_CLK_ENB) != 0) {
- opt &= ~OPT_CFG_CLK_ENB;
- CSR_WRITE_4(sc, ALC_OPT_CFG, opt);
- CSR_READ_4(sc, ALC_OPT_CFG);
- DELAY(1000);
+ if (eeprom != 0) {
+ switch (sc->alc_ident->deviceid) {
+ case PCI_PRODUCT_ATTANSIC_AR8131:
+ case PCI_PRODUCT_ATTANSIC_AR8132:
+ if ((opt & OPT_CFG_CLK_ENB) != 0) {
+ opt &= ~OPT_CFG_CLK_ENB;
+ CSR_WRITE_4(sc, ALC_OPT_CFG, opt);
+ CSR_READ_4(sc, ALC_OPT_CFG);
+ DELAY(1000);
+ }
+ break;
+ case PCI_PRODUCT_ATTANSIC_AR8151:
+ case PCI_PRODUCT_ATTANSIC_AR8151_V2:
+ case PCI_PRODUCT_ATTANSIC_AR8152_B:
+ case PCI_PRODUCT_ATTANSIC_AR8152_B2:
+ alc_miibus_writereg(sc->sc_dev, sc->alc_phyaddr,
+ ALC_MII_DBG_ADDR, 0x00);
+ val = alc_miibus_readreg(sc->sc_dev, sc->alc_phyaddr,
+ ALC_MII_DBG_DATA);
+ alc_miibus_writereg(sc->sc_dev, sc->alc_phyaddr,
+ ALC_MII_DBG_DATA, val | 0x0080);
+ alc_miibus_writereg(sc->sc_dev, sc->alc_phyaddr,
+ ALC_MII_DBG_ADDR, 0x3B);
+ val = alc_miibus_readreg(sc->sc_dev, sc->alc_phyaddr,
+ ALC_MII_DBG_DATA);
+ alc_miibus_writereg(sc->sc_dev, sc->alc_phyaddr,
+ ALC_MII_DBG_DATA, val & 0xFFF7);
+ DELAY(20);
+ break;
+ }
}
ea[0] = CSR_READ_4(sc, ALC_PAR0);
@@ -363,6 +446,43 @@
CSR_READ_2(sc, ALC_GPHY_CFG);
DELAY(10 * 1000);
+ /* DSP fixup, Vendor magic. */
+ if (sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8152_B) {
+ alc_miibus_writereg(sc->sc_dev, sc->alc_phyaddr,
+ ALC_MII_DBG_ADDR, 0x000A);
+ data = alc_miibus_readreg(sc->sc_dev, sc->alc_phyaddr,
+ ALC_MII_DBG_DATA);
+ alc_miibus_writereg(sc->sc_dev, sc->alc_phyaddr,
+ ALC_MII_DBG_DATA, data & 0xDFFF);
+ }
+ if (sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8151 ||
+ sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8151_V2 ||
+ sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8152_B ||
+ sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8152_B2) {
+ alc_miibus_writereg(sc->sc_dev, sc->alc_phyaddr,
+ ALC_MII_DBG_ADDR, 0x003B);
+ data = alc_miibus_readreg(sc->sc_dev, sc->alc_phyaddr,
+ ALC_MII_DBG_DATA);
+ alc_miibus_writereg(sc->sc_dev, sc->alc_phyaddr,
+ ALC_MII_DBG_DATA, data & 0xFFF7);
+ DELAY(20 * 1000);
+ }
+ if (sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8151) {
+ alc_miibus_writereg(sc->sc_dev, sc->alc_phyaddr,
+ ALC_MII_DBG_ADDR, 0x0029);
+ alc_miibus_writereg(sc->sc_dev, sc->alc_phyaddr,
+ ALC_MII_DBG_DATA, 0x929D);
+ }
+ if (sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8131 ||
+ sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8132 ||
+ sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8151_V2 ||
+ sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8152_B2) {
+ alc_miibus_writereg(sc->sc_dev, sc->alc_phyaddr,
+ ALC_MII_DBG_ADDR, 0x0029);
+ alc_miibus_writereg(sc->sc_dev, sc->alc_phyaddr,
+ 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);
@@ -411,35 +531,115 @@
static void
alc_phy_down(struct alc_softc *sc)
{
-
- /* Force PHY down. */
- CSR_WRITE_2(sc, ALC_GPHY_CFG,
- GPHY_CFG_EXT_RESET | GPHY_CFG_HIB_EN | GPHY_CFG_HIB_PULSE |
- GPHY_CFG_SEL_ANA_RESET | GPHY_CFG_PHY_IDDQ | GPHY_CFG_PWDOWN_HW);
- DELAY(1000);
+ switch (sc->alc_ident->deviceid) {
+ case PCI_PRODUCT_ATTANSIC_AR8151:
+ case PCI_PRODUCT_ATTANSIC_AR8151_V2:
+ /*
+ * GPHY power down caused more problems on AR8151 v2.0.
+ * When driver is reloaded after GPHY power down,
+ * accesses to PHY/MAC registers hung the system. Only
+ * cold boot recovered from it. I'm not sure whether
+ * AR8151 v1.0 also requires this one though. I don't
+ * have AR8151 v1.0 controller in hand.
+ * The only option left is to isolate the PHY and
+ * initiates power down the PHY which in turn saves
+ * more power when driver is unloaded.
+ */
+ alc_miibus_writereg(sc->sc_dev, sc->alc_phyaddr,
+ MII_BMCR, BMCR_ISO | BMCR_PDOWN);
+ break;
+ default:
+ /* Force PHY down. */
+ CSR_WRITE_2(sc, ALC_GPHY_CFG,
+ GPHY_CFG_EXT_RESET | GPHY_CFG_HIB_EN | GPHY_CFG_HIB_PULSE |
+ GPHY_CFG_SEL_ANA_RESET | GPHY_CFG_PHY_IDDQ |
+ GPHY_CFG_PWDOWN_HW);
+ DELAY(1000);
+ break;
+ }
}
static void
-alc_aspm(struct alc_softc *sc)
+alc_aspm(struct alc_softc *sc, int media)
{
uint32_t pmcfg;
-
+ uint16_t linkcfg;
+
pmcfg = CSR_READ_4(sc, ALC_PM_CFG);
+ if ((sc->alc_flags & (ALC_FLAG_APS | ALC_FLAG_PCIE)) ==
+ (ALC_FLAG_APS | ALC_FLAG_PCIE))
Home |
Main Index |
Thread Index |
Old Index