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