Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/pci add network driver for Atheros AR813x/AR815x eth...



details:   https://anonhg.NetBSD.org/src/rev/ad46b1e59dd0
branches:  trunk
changeset: 762550:ad46b1e59dd0
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Wed Feb 23 00:35:29 2011 +0000

description:
add network driver for Atheros AR813x/AR815x ethernet controllers, based
on a patch from fire crow on tech-net with additional bpf & detach fixes,
module support, and a match for 8152 v2.0 devices.

alc0 at pci3 dev 0 function 0: Attansic/Atheros L1C/L2C Ethernet
alc0: ioapic0 pin 17
alc0: Ethernet address 00:26:6c:9e:d4:c1
ukphy0 at alc0 phy 0: L2 10/100 PHY (OUI 0x00c82e, model 0x0002), rev. 5
ukphy0: 10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, 1000baseT-FDX, auto

diffstat:

 sys/dev/pci/files.pci   |     7 +-
 sys/dev/pci/if_alc.c    |  2414 +++++++++++++++++++++++++++++++++++++++++++++++
 sys/dev/pci/if_alcreg.h |  1173 ++++++++++++++++++++++
 3 files changed, 3593 insertions(+), 1 deletions(-)

diffs (truncated from 3616 to 300 lines):

diff -r eca769446c51 -r ad46b1e59dd0 sys/dev/pci/files.pci
--- a/sys/dev/pci/files.pci     Tue Feb 22 23:57:22 2011 +0000
+++ b/sys/dev/pci/files.pci     Wed Feb 23 00:35:29 2011 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: files.pci,v 1.338 2011/02/09 21:21:32 macallan Exp $
+#      $NetBSD: files.pci,v 1.339 2011/02/23 00:35:29 jmcneill Exp $
 #
 # Config file and device description for machine-independent PCI code.
 # Included by ports that need it.  Requires that the SCSI files be
@@ -969,6 +969,11 @@
 attach age at pci
 file   dev/pci/if_age.c                age
 
+# Attansic/Atheros L1C/L2C Gigabit Ethernet
+device alc: ether, ifnet, arp, mii, mii_phy
+attach alc at pci
+file   dev/pci/if_alc.c                alc
+
 # Attanisc/Atheros L1E Gigabit Ethernet
 device ale: ether, ifnet, arp, mii, mii_phy
 attach ale at pci
diff -r eca769446c51 -r ad46b1e59dd0 sys/dev/pci/if_alc.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/pci/if_alc.c      Wed Feb 23 00:35:29 2011 +0000
@@ -0,0 +1,2414 @@
+/*     $OpenBSD: if_alc.c,v 1.1 2009/08/08 09:31:13 kevlo Exp $        */
+/*-
+ * Copyright (c) 2009, Pyun YongHyeon <yongari%FreeBSD.org@localhost>
+ * 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.
+ */
+
+/* Driver for Atheros AR8131/AR8132 PCIe Ethernet. */
+
+#ifdef _KERNEL_OPT
+#include "vlan.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/endian.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/queue.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/callout.h>
+#include <sys/socket.h>
+#include <sys/module.h>
+
+#include <sys/bus.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_llc.h>
+#include <net/if_media.h>
+#include <net/if_ether.h>
+
+#include <net/bpf.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#endif
+
+#include <net/if_types.h>
+#include <net/if_vlanvar.h>
+
+#include <net/bpf.h>
+
+#include <sys/rnd.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+
+#include <dev/pci/if_alcreg.h>
+
+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);
+
+static int     alc_init(struct ifnet *);
+static void    alc_start(struct ifnet *);
+static int     alc_ioctl(struct ifnet *, u_long, void *);
+static void    alc_watchdog(struct ifnet *);
+static int     alc_mediachange(struct ifnet *);
+static void    alc_mediastatus(struct ifnet *, struct ifmediareq *);
+
+static void    alc_aspm(struct alc_softc *);
+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 void    alc_get_macaddr(struct alc_softc *);
+static void    alc_init_cmb(struct alc_softc *);
+static void    alc_init_rr_ring(struct alc_softc *);
+static int     alc_init_rx_ring(struct alc_softc *);
+static void    alc_init_smb(struct alc_softc *);
+static void    alc_init_tx_ring(struct alc_softc *);
+static int     alc_intr(void *);
+static void    alc_mac_config(struct alc_softc *);
+static int     alc_miibus_readreg(device_t, int, int);
+static void    alc_miibus_statchg(device_t);
+static void    alc_miibus_writereg(device_t, int, int, int);
+static int     alc_newbuf(struct alc_softc *, struct alc_rxdesc *, int);
+static void    alc_phy_down(struct alc_softc *);
+static void    alc_phy_reset(struct alc_softc *);
+static void    alc_reset(struct alc_softc *);
+static void    alc_rxeof(struct alc_softc *, struct rx_rdesc *);
+static int     alc_rxintr(struct alc_softc *);
+static void    alc_iff(struct alc_softc *);
+static void    alc_rxvlan(struct alc_softc *);
+static void    alc_start_queue(struct alc_softc *);
+static void    alc_stats_clear(struct alc_softc *);
+static void    alc_stats_update(struct alc_softc *);
+static void    alc_stop(struct ifnet *, int);
+static void    alc_stop_mac(struct alc_softc *);
+static void    alc_stop_queue(struct alc_softc *);
+static void    alc_tick(void *);
+static void    alc_txeof(struct alc_softc *);
+
+uint32_t alc_dma_burst[] = { 128, 256, 512, 1024, 2048, 4096, 0 };
+
+CFATTACH_DECL_NEW(alc, sizeof(struct alc_softc),
+    alc_match, alc_attach, alc_detach, NULL);
+
+int alcdebug = 0;
+#define        DPRINTF(x)      do { if (alcdebug) printf x; } while (0)
+
+#define ETHER_ALIGN            2
+#define ALC_CSUM_FEATURES      (M_CSUM_TCPv4 | M_CSUM_UDPv4)
+
+static int
+alc_miibus_readreg(device_t dev, int phy, int reg)
+{
+       struct alc_softc *sc = device_private(dev);
+       uint32_t v;
+       int i;
+
+       if (phy != sc->alc_phyaddr)
+               return (0);
+
+       CSR_WRITE_4(sc, 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--) {
+               DELAY(5);
+               v = CSR_READ_4(sc, ALC_MDIO);
+               if ((v & (MDIO_OP_EXECUTE | MDIO_OP_BUSY)) == 0)
+                       break;
+       }
+
+       if (i == 0) {
+               printf("%s: phy read timeout: phy %d, reg %d\n",
+                   device_xname(sc->sc_dev), phy, reg);
+               return (0);
+       }
+
+       return ((v & MDIO_DATA_MASK) >> MDIO_DATA_SHIFT);
+}
+
+static void
+alc_miibus_writereg(device_t dev, int phy, int reg, int val)
+{
+       struct alc_softc *sc = device_private(dev);
+       uint32_t v;
+       int i;
+
+       if (phy != sc->alc_phyaddr)
+               return;
+
+       CSR_WRITE_4(sc, 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--) {
+               DELAY(5);
+               v = CSR_READ_4(sc, ALC_MDIO);
+               if ((v & (MDIO_OP_EXECUTE | MDIO_OP_BUSY)) == 0)
+                       break;
+       }
+
+       if (i == 0)
+               printf("%s: phy write timeout: phy %d, reg %d\n",
+                   device_xname(sc->sc_dev), phy, reg);
+}
+
+static void
+alc_miibus_statchg(device_t dev)
+{
+       struct alc_softc *sc = device_private(dev);
+       struct ifnet *ifp = &sc->sc_ec.ec_if;
+       struct mii_data *mii;
+       uint32_t reg;
+
+       if ((ifp->if_flags & IFF_RUNNING) == 0)
+               return;
+
+       mii = &sc->sc_miibus;
+
+       sc->alc_flags &= ~ALC_FLAG_LINK;
+       if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
+           (IFM_ACTIVE | IFM_AVALID)) {
+               switch (IFM_SUBTYPE(mii->mii_media_active)) {
+               case IFM_10_T:
+               case IFM_100_TX:
+                       sc->alc_flags |= ALC_FLAG_LINK;
+                       break;
+               case IFM_1000_T:
+                       if ((sc->alc_flags & ALC_FLAG_FASTETHER) == 0)
+                               sc->alc_flags |= ALC_FLAG_LINK;
+                       break;
+               default:
+                       break;
+               }
+       }
+       alc_stop_queue(sc);
+       /* Stop Rx/Tx MACs. */
+       alc_stop_mac(sc);
+
+       /* Program MACs with resolved speed/duplex/flow-control. */
+       if ((sc->alc_flags & ALC_FLAG_LINK) != 0) {
+               alc_start_queue(sc);
+               alc_mac_config(sc);
+               /* Re-enable Tx/Rx MACs. */
+               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);
+}
+
+static void
+alc_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+       struct alc_softc *sc = ifp->if_softc;
+       struct mii_data *mii = &sc->sc_miibus;
+
+       mii_pollstat(mii);
+       ifmr->ifm_status = mii->mii_media_status;
+       ifmr->ifm_active = mii->mii_media_active;
+}
+
+static int
+alc_mediachange(struct ifnet *ifp)
+{
+       struct alc_softc *sc = ifp->if_softc;
+       struct mii_data *mii = &sc->sc_miibus;
+       int error;
+
+       if (mii->mii_instance != 0) {
+               struct mii_softc *miisc;
+
+               LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
+                       mii_phy_reset(miisc);
+       }
+       error = mii_mediachg(mii);
+
+       return (error);
+}
+
+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:



Home | Main Index | Thread Index | Old Index