[haiku-commits] r34348 - in haiku/trunk/src/add-ons/kernel/drivers/network: . atheros813x atheros813x/dev atheros813x/dev/alc atheros813x/dev/mii

  • From: coling@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sun, 29 Nov 2009 14:35:30 +0100 (CET)

Author: colin
Date: 2009-11-29 14:35:30 +0100 (Sun, 29 Nov 2009)
New Revision: 34348
Changeset: http://dev.haiku-os.org/changeset/34348/haiku

Added:
   haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/
   haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/Jamfile
   haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/
   haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/Jamfile
   haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/
   haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/Jamfile
   haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/glue.c
   haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/if_alc.c
   
haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/if_alcreg.h
   
haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/if_alcvar.h
   haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/mii/
   haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/mii/Jamfile
   haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/mii/ukphy.c
   
haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/mii/ukphy_subr.c
Modified:
   haiku/trunk/src/add-ons/kernel/drivers/network/Jamfile
Log:
* Adding driver for Atheros AR8131/AR8132 Gigabit/Fast Ethernet network cards.
  The source is based on the FreeBSD RELEASE_8_0_0 code, found in Haiku's
  freebsd vendor branch.
  This driver enables the network card in my EeePC 1005HA-M, for example.
  To compile it issue "jam atheros813x".
* Introducing the new build target.


Modified: haiku/trunk/src/add-ons/kernel/drivers/network/Jamfile
===================================================================
--- haiku/trunk/src/add-ons/kernel/drivers/network/Jamfile      2009-11-29 
12:40:32 UTC (rev 34347)
+++ haiku/trunk/src/add-ons/kernel/drivers/network/Jamfile      2009-11-29 
13:35:30 UTC (rev 34348)
@@ -31,4 +31,7 @@
 SubIncludeGPL HAIKU_TOP src add-ons kernel drivers network bcm440x ;
 SubIncludeGPL HAIKU_TOP src add-ons kernel drivers network bcm570x ;
 
+# FreeBSD 8 drivers
+SubInclude HAIKU_TOP src add-ons kernel drivers network atheros813x ;
+
 SubInclude HAIKU_TOP src add-ons kernel drivers network wlan ;

Added: haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/Jamfile
===================================================================
--- haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/Jamfile          
                (rev 0)
+++ haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/Jamfile  
2009-11-29 13:35:30 UTC (rev 34348)
@@ -0,0 +1,3 @@
+SubDir HAIKU_TOP src add-ons kernel drivers network atheros813x ;
+
+SubInclude HAIKU_TOP src add-ons kernel drivers network atheros813x dev ;

Added: haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/Jamfile
===================================================================
--- haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/Jamfile      
                        (rev 0)
+++ haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/Jamfile      
2009-11-29 13:35:30 UTC (rev 34348)
@@ -0,0 +1,4 @@
+SubDir HAIKU_TOP src add-ons kernel drivers network atheros813x dev ;
+
+SubInclude HAIKU_TOP src add-ons kernel drivers network atheros813x dev mii ;
+SubInclude HAIKU_TOP src add-ons kernel drivers network atheros813x dev alc ;

Added: 
haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/Jamfile
===================================================================
--- haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/Jamfile  
                        (rev 0)
+++ haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/Jamfile  
2009-11-29 13:35:30 UTC (rev 34348)
@@ -0,0 +1,19 @@
+SubDir HAIKU_TOP src add-ons kernel drivers network atheros813x dev alc ;
+
+SubDirCcFlags -Wall ;
+
+UseHeaders [ FDirName $(HAIKU_TOP) src libs compat freebsd_network compat ] : 
true ;
+
+UsePrivateHeaders net system ;
+UsePrivateKernelHeaders ;
+
+UseHeaders [ FDirName $(SUBDIR) .. .. ] : true ;
+
+SubDirCcFlags [ FDefines _KERNEL=1 ] ;
+
+KernelAddon atheros813x :
+       if_alc.c
+       glue.c
+       : libfreebsd_network.a atheros813x_mii.a
+       ;
+

Added: haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/glue.c
===================================================================
--- haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/glue.c   
                        (rev 0)
+++ haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/glue.c   
2009-11-29 13:35:30 UTC (rev 34348)
@@ -0,0 +1,8 @@
+#include <sys/bus.h>
+
+HAIKU_FBSD_DRIVER_GLUE(atheros813x, alc, pci);
+
+HAIKU_FBSD_MII_DRIVER(ukphy);
+HAIKU_DRIVER_REQUIREMENTS(FBSD_TASKQUEUES | FBSD_FAST_TASKQUEUE);
+NO_HAIKU_CHECK_DISABLE_INTERRUPTS();
+NO_HAIKU_REENABLE_INTERRUPTS();

Added: 
haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/if_alc.c
===================================================================
--- haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/if_alc.c 
                        (rev 0)
+++ haiku/trunk/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/if_alc.c 
2009-11-29 13:35:30 UTC (rev 34348)
@@ -0,0 +1,3512 @@
+/*-
+ * Copyright (c) 2009, Pyun YongHyeon <yongari@xxxxxxxxxxx>
+ * 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. */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <sys/taskqueue.h>
+
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_llc.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_vlan_var.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <machine/atomic.h>
+#include <machine/bus.h>
+#include <machine/in_cksum.h>
+
+#include <dev/alc/if_alcreg.h>
+#include <dev/alc/if_alcvar.h>
+
+/* "device miibus" required.  See GENERIC if you get errors here. */
+#include "miibus_if.h"
+#undef ALC_USE_CUSTOM_CSUM
+
+#ifdef ALC_USE_CUSTOM_CSUM
+#define        ALC_CSUM_FEATURES       (CSUM_TCP | CSUM_UDP)
+#else
+#define        ALC_CSUM_FEATURES       (CSUM_IP | CSUM_TCP | CSUM_UDP)
+#endif
+#ifndef        IFCAP_VLAN_HWTSO
+#define        IFCAP_VLAN_HWTSO        0
+#endif
+
+MODULE_DEPEND(alc, pci, 1, 1, 1);
+MODULE_DEPEND(alc, ether, 1, 1, 1);
+MODULE_DEPEND(alc, miibus, 1, 1, 1);
+
+/* Tunables. */
+static int msi_disable = 0;
+static int msix_disable = 0;
+TUNABLE_INT("hw.alc.msi_disable", &msi_disable);
+TUNABLE_INT("hw.alc.msix_disable", &msix_disable);
+
+/*
+ * Devices supported by this driver.
+ */
+static struct alc_dev {
+       uint16_t        alc_vendorid;
+       uint16_t        alc_deviceid;
+       const char      *alc_name;
+} alc_devs[] = {
+       { VENDORID_ATHEROS, DEVICEID_ATHEROS_AR8131,
+               "Atheros AR8131 PCIe Gigabit Ethernet" },
+       { VENDORID_ATHEROS, DEVICEID_ATHEROS_AR8132,
+               "Atheros AR8132 PCIe Fast Ethernet" }
+};
+
+static void    alc_aspm(struct alc_softc *);
+static int     alc_attach(device_t);
+static int     alc_check_boundary(struct alc_softc *);
+static int     alc_detach(device_t);
+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 void    alc_dmamap_cb(void *, bus_dma_segment_t *, int, int);
+static int     alc_encap(struct alc_softc *, struct mbuf **);
+#ifndef __NO_STRICT_ALIGNMENT
+static struct mbuf *
+               alc_fixup_rx(struct ifnet *, struct mbuf *);
+#endif
+static void    alc_get_macaddr(struct alc_softc *);
+static void    alc_init(void *);
+static void    alc_init_cmb(struct alc_softc *);
+static void    alc_init_locked(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 void    alc_int_task(void *, int);
+static int     alc_intr(void *);
+static int     alc_ioctl(struct ifnet *, u_long, caddr_t);
+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 int     alc_miibus_writereg(device_t, int, int, int);
+static int     alc_mediachange(struct ifnet *);
+static void    alc_mediastatus(struct ifnet *, struct ifmediareq *);
+static int     alc_newbuf(struct alc_softc *, struct alc_rxdesc *);
+static void    alc_phy_down(struct alc_softc *);
+static void    alc_phy_reset(struct alc_softc *);
+static int     alc_probe(device_t);
+static void    alc_reset(struct alc_softc *);
+static int     alc_resume(device_t);
+static void    alc_rxeof(struct alc_softc *, struct rx_rdesc *);
+static int     alc_rxintr(struct alc_softc *, int);
+static void    alc_rxfilter(struct alc_softc *);
+static void    alc_rxvlan(struct alc_softc *);
+static void    alc_setlinkspeed(struct alc_softc *);
+static void    alc_setwol(struct alc_softc *);
+static int     alc_shutdown(device_t);
+static void    alc_start(struct ifnet *);
+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 alc_softc *);
+static void    alc_stop_mac(struct alc_softc *);
+static void    alc_stop_queue(struct alc_softc *);
+static int     alc_suspend(device_t);
+static void    alc_sysctl_node(struct alc_softc *);
+static void    alc_tick(void *);
+static void    alc_tx_task(void *, int);
+static void    alc_txeof(struct alc_softc *);
+static void    alc_watchdog(struct alc_softc *);
+static int     sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int);
+static int     sysctl_hw_alc_proc_limit(SYSCTL_HANDLER_ARGS);
+static int     sysctl_hw_alc_int_mod(SYSCTL_HANDLER_ARGS);
+
+static device_method_t alc_methods[] = {
+       /* Device interface. */
+       DEVMETHOD(device_probe,         alc_probe),
+       DEVMETHOD(device_attach,        alc_attach),
+       DEVMETHOD(device_detach,        alc_detach),
+       DEVMETHOD(device_shutdown,      alc_shutdown),
+       DEVMETHOD(device_suspend,       alc_suspend),
+       DEVMETHOD(device_resume,        alc_resume),
+
+       /* MII interface. */
+       DEVMETHOD(miibus_readreg,       alc_miibus_readreg),
+       DEVMETHOD(miibus_writereg,      alc_miibus_writereg),
+       DEVMETHOD(miibus_statchg,       alc_miibus_statchg),
+
+       { NULL, NULL }
+};
+
+static driver_t alc_driver = {
+       "alc",
+       alc_methods,
+       sizeof(struct alc_softc)
+};
+
+static devclass_t alc_devclass;
+
+DRIVER_MODULE(alc, pci, alc_driver, alc_devclass, 0, 0);
+DRIVER_MODULE(miibus, alc, miibus_driver, miibus_devclass, 0, 0);
+
+static struct resource_spec alc_res_spec_mem[] = {
+       { SYS_RES_MEMORY,       PCIR_BAR(0),    RF_ACTIVE },
+       { -1,                   0,              0 }
+};
+
+static struct resource_spec alc_irq_spec_legacy[] = {
+       { SYS_RES_IRQ,          0,              RF_ACTIVE | RF_SHAREABLE },
+       { -1,                   0,              0 }
+};
+
+static struct resource_spec alc_irq_spec_msi[] = {
+       { SYS_RES_IRQ,          1,              RF_ACTIVE },
+       { -1,                   0,              0 }
+};
+
+static struct resource_spec alc_irq_spec_msix[] = {
+       { SYS_RES_IRQ,          1,              RF_ACTIVE },
+       { -1,                   0,              0 }
+};
+
+static uint32_t alc_dma_burst[] = { 128, 256, 512, 1024, 2048, 4096, 0 };
+
+static int
+alc_miibus_readreg(device_t dev, int phy, int reg)
+{
+       struct alc_softc *sc;
+       uint32_t v;
+       int i;
+
+       sc = device_get_softc(dev);
+
+       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) {
+               device_printf(sc->alc_dev, "phy read timeout : %d\n", reg);
+               return (0);
+       }
+
+       return ((v & MDIO_DATA_MASK) >> MDIO_DATA_SHIFT);
+}
+
+static int
+alc_miibus_writereg(device_t dev, int phy, int reg, int val)
+{
+       struct alc_softc *sc;
+       uint32_t v;
+       int i;
+
+       sc = device_get_softc(dev);
+
+       if (phy != sc->alc_phyaddr)
+               return (0);
+
+       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)
+               device_printf(sc->alc_dev, "phy write timeout : %d\n", reg);
+
+       return (0);
+}
+
+static void
+alc_miibus_statchg(device_t dev)
+{
+       struct alc_softc *sc;
+       struct mii_data *mii;
+       struct ifnet *ifp;
+       uint32_t reg;
+
+       sc = device_get_softc(dev);
+
+       mii = device_get_softc(sc->alc_miibus);
+       ifp = sc->alc_ifp;
+       if (mii == NULL || ifp == NULL ||
+           (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+               return;
+
+       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;
+       struct mii_data *mii;
+
+       sc = ifp->if_softc;
+       ALC_LOCK(sc);
+       if ((ifp->if_flags & IFF_UP) == 0) {
+               ALC_UNLOCK(sc);
+               return;
+       }
+       mii = device_get_softc(sc->alc_miibus);
+
+       mii_pollstat(mii);
+       ALC_UNLOCK(sc);
+       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;
+       struct mii_data *mii;
+       struct mii_softc *miisc;
+       int error;
+
+       sc = ifp->if_softc;
+       ALC_LOCK(sc);
+       mii = device_get_softc(sc->alc_miibus);
+       if (mii->mii_instance != 0) {
+               LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
+                       mii_phy_reset(miisc);
+       }
+       error = mii_mediachg(mii);
+       ALC_UNLOCK(sc);
+
+       return (error);
+}
+
+static int
+alc_probe(device_t dev)
+{
+       struct alc_dev *sp;
+       int i;
+       uint16_t vendor, devid;
+
+       vendor = pci_get_vendor(dev);
+       devid = pci_get_device(dev);
+       sp = alc_devs;
+       for (i = 0; i < sizeof(alc_devs) / sizeof(alc_devs[0]); i++) {
+               if (vendor == sp->alc_vendorid &&
+                   devid == sp->alc_deviceid) {
+                       device_set_desc(dev, sp->alc_name);
+                       return (BUS_PROBE_DEFAULT);
+               }
+               sp++;
+       }
+
+       return (ENXIO);
+}
+
+static void
+alc_get_macaddr(struct alc_softc *sc)
+{
+       uint32_t ea[2], opt;
+       int i;
+
+       opt = CSR_READ_4(sc, ALC_OPT_CFG);
+       if ((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);
+               }
+               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--) {
+                       DELAY(1000);
+                       if ((CSR_READ_4(sc, ALC_TWSI_CFG) &
+                           TWSI_CFG_SW_LD_START) == 0)
+                               break;
+               }
+               if (i == 0)
+                       device_printf(sc->alc_dev,
+                           "reloading EEPROM timeout!\n");
+       } else {
+               if (bootverbose)
+                       device_printf(sc->alc_dev, "EEPROM not found!\n");
+       }
+       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);
+       }
+
+       ea[0] = CSR_READ_4(sc, ALC_PAR0);
+       ea[1] = CSR_READ_4(sc, ALC_PAR1);
+       sc->alc_eaddr[0] = (ea[1] >> 8) & 0xFF;
+       sc->alc_eaddr[1] = (ea[1] >> 0) & 0xFF;
+       sc->alc_eaddr[2] = (ea[0] >> 24) & 0xFF;
+       sc->alc_eaddr[3] = (ea[0] >> 16) & 0xFF;
+       sc->alc_eaddr[4] = (ea[0] >> 8) & 0xFF;
+       sc->alc_eaddr[5] = (ea[0] >> 0) & 0xFF;
+}
+
+static void
+alc_disable_l0s_l1(struct alc_softc *sc)
+{
+       uint32_t pmcfg;
+
+       /* Another magic from vendor. */
+       pmcfg = CSR_READ_4(sc, 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;
+       CSR_WRITE_4(sc, ALC_PM_CFG, pmcfg);
+}
+
+static void
+alc_phy_reset(struct alc_softc *sc)
+{
+       uint16_t data;
+
+       /* Reset magic from Linux. */
+       CSR_WRITE_2(sc, ALC_GPHY_CFG,
+           GPHY_CFG_HIB_EN | GPHY_CFG_HIB_PULSE | GPHY_CFG_SEL_ANA_RESET);
+       CSR_READ_2(sc, ALC_GPHY_CFG);
+       DELAY(10 * 1000);
+
+       CSR_WRITE_2(sc, ALC_GPHY_CFG,
+           GPHY_CFG_EXT_RESET | GPHY_CFG_HIB_EN | GPHY_CFG_HIB_PULSE |
+           GPHY_CFG_SEL_ANA_RESET);
+       CSR_READ_2(sc, ALC_GPHY_CFG);
+       DELAY(10 * 1000);
+
+       /* 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);
+       alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr,
+           ALC_MII_DBG_ADDR, MII_ANA_CFG18);
+       alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr,
+           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;
+       alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr,
+           ALC_MII_DBG_ADDR, MII_ANA_CFG5);
+       alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr,
+           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;
+       alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr,
+           ALC_MII_DBG_ADDR, MII_ANA_CFG54);
+       alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr,
+           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);
+       alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr,
+           ALC_MII_DBG_ADDR, MII_ANA_CFG4);
+       alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr,
+           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;
+       alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr,
+           ALC_MII_DBG_ADDR, MII_ANA_CFG0);
+       alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr,
+           ALC_MII_DBG_DATA, data);
+       DELAY(1000);
+}
+
+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);
+}
+
+static void
+alc_aspm(struct alc_softc *sc)
+{
+       uint32_t pmcfg;
+
+       ALC_LOCK_ASSERT(sc);
+
+       pmcfg = CSR_READ_4(sc, ALC_PM_CFG);
+       pmcfg &= ~PM_CFG_SERDES_PD_EX_L1;
+       pmcfg |= PM_CFG_SERDES_BUDS_RX_L1_ENB;
+       pmcfg |= PM_CFG_SERDES_L1_ENB;
+       pmcfg &= ~PM_CFG_L1_ENTRY_TIMER_MASK;
+       pmcfg |= PM_CFG_MAC_ASPM_CHK;
+       if ((sc->alc_flags & ALC_FLAG_LINK) != 0) {
+               pmcfg |= PM_CFG_SERDES_PLL_L1_ENB;
+               pmcfg &= ~PM_CFG_CLK_SWH_L1;
+               pmcfg &= ~PM_CFG_ASPM_L1_ENB;
+               pmcfg &= ~PM_CFG_ASPM_L0S_ENB;
+       } else {
+               pmcfg &= ~PM_CFG_SERDES_PLL_L1_ENB;
+               pmcfg |= PM_CFG_CLK_SWH_L1;
+               pmcfg &= ~PM_CFG_ASPM_L1_ENB;
+               pmcfg &= ~PM_CFG_ASPM_L0S_ENB;
+       }
+       CSR_WRITE_4(sc, ALC_PM_CFG, pmcfg);
+}
+
+static int
+alc_attach(device_t dev)
+{
+       struct alc_softc *sc;
+       struct ifnet *ifp;
+       char *aspm_state[] = { "L0s/L1", "L0s", "L1", "L0s/l1" };
+       uint16_t burst;
+       int base, error, i, msic, msixc, pmc, state;
+       uint32_t cap, ctl, val;
+
+       error = 0;
+       sc = device_get_softc(dev);
+       sc->alc_dev = dev;
+
+       mtx_init(&sc->alc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+           MTX_DEF);
+       callout_init_mtx(&sc->alc_tick_ch, &sc->alc_mtx, 0);
+       TASK_INIT(&sc->alc_int_task, 0, alc_int_task, sc);
+
+       /* Map the device. */
+       pci_enable_busmaster(dev);
+       sc->alc_res_spec = alc_res_spec_mem;
+       sc->alc_irq_spec = alc_irq_spec_legacy;
+       error = bus_alloc_resources(dev, sc->alc_res_spec, sc->alc_res);
+       if (error != 0) {
+               device_printf(dev, "cannot allocate memory resources.\n");
+               goto fail;
+       }
+
+       /* Set PHY address. */
+       sc->alc_phyaddr = ALC_PHY_ADDR;
+
+       /* Initialize DMA parameters. */
+       sc->alc_dma_rd_burst = 0;
+       sc->alc_dma_wr_burst = 0;
+       sc->alc_rcb = DMA_CFG_RCB_64;
+       if (pci_find_extcap(dev, PCIY_EXPRESS, &base) == 0) {
+               sc->alc_flags |= ALC_FLAG_PCIE;
+               burst = CSR_READ_2(sc, base + PCIR_EXPRESS_DEVICE_CTL);
+               sc->alc_dma_rd_burst =
+                   (burst & PCIM_EXP_CTL_MAX_READ_REQUEST) >> 12;
+               sc->alc_dma_wr_burst = (burst & PCIM_EXP_CTL_MAX_PAYLOAD) >> 5;
+               if (bootverbose) {
+                       device_printf(dev, "Read request size : %u bytes.\n",
+                           alc_dma_burst[sc->alc_dma_rd_burst]);
+                       device_printf(dev, "TLP payload size : %u bytes.\n",
+                           alc_dma_burst[sc->alc_dma_wr_burst]);
+               }
+               /* Clear data link and flow-control protocol error. */
+               val = CSR_READ_4(sc, ALC_PEX_UNC_ERR_SEV);
+               val &= ~(PEX_UNC_ERR_SEV_DLP | PEX_UNC_ERR_SEV_FCP);
+               CSR_WRITE_4(sc, ALC_PEX_UNC_ERR_SEV, val);
+               /* Disable ASPM L0S and L1. */
+               cap = CSR_READ_2(sc, base + PCIR_EXPRESS_LINK_CAP);
+               if ((cap & PCIM_LINK_CAP_ASPM) != 0) {
+                       ctl = CSR_READ_2(sc, base + PCIR_EXPRESS_LINK_CTL);
+                       if ((ctl & 0x08) != 0)
+                               sc->alc_rcb = DMA_CFG_RCB_128;
+                       if (bootverbose)
+                               device_printf(dev, "RCB %u bytes\n",
+                                   sc->alc_rcb == DMA_CFG_RCB_64 ? 64 : 128);
+                       state = ctl & 0x03;
+                       if (bootverbose)
+                               device_printf(sc->alc_dev, "ASPM %s %s\n",
+                                   aspm_state[state],
+                                   state == 0 ? "disabled" : "enabled");
+                       if (state != 0)
+                               alc_disable_l0s_l1(sc);
+               }
+       }
+
+       /* Reset PHY. */
+       alc_phy_reset(sc);
+
+       /* Reset the ethernet controller. */
+       alc_reset(sc);
+
+       /*
+        * One odd thing is AR8132 uses the same PHY hardware(F1
+        * gigabit PHY) of AR8131. So atphy(4) of AR8132 reports
+        * the PHY supports 1000Mbps but that's not true. The PHY
+        * used in AR8132 can't establish gigabit link even if it
+        * shows the same PHY model/revision number of AR8131.
+        */
+       if (pci_get_device(dev) == DEVICEID_ATHEROS_AR8132)
+               sc->alc_flags |= ALC_FLAG_FASTETHER | ALC_FLAG_JUMBO;
+       else
+               sc->alc_flags |= ALC_FLAG_JUMBO | ALC_FLAG_ASPM_MON;
+       /*
+        * It seems that AR8131/AR8132 has silicon bug for SMB. In
+        * addition, Atheros said that enabling SMB wouldn't improve
+        * performance. However I think it's bad to access lots of
+        * registers to extract MAC statistics.
+        */
+       sc->alc_flags |= ALC_FLAG_SMB_BUG;
+       /*
+        * Don't use Tx CMB. It is known to have silicon bug.
+        */
+       sc->alc_flags |= ALC_FLAG_CMB_BUG;
+       sc->alc_rev = pci_get_revid(dev);
+       sc->alc_chip_rev = CSR_READ_4(sc, ALC_MASTER_CFG) >>
+           MASTER_CHIP_REV_SHIFT;
+       if (bootverbose) {
+               device_printf(dev, "PCI device revision : 0x%04x\n",
+                   sc->alc_rev);
+               device_printf(dev, "Chip id/revision : 0x%04x\n",
+                   sc->alc_chip_rev);
+       }
+       device_printf(dev, "%u Tx FIFO, %u Rx FIFO\n",
+           CSR_READ_4(sc, ALC_SRAM_TX_FIFO_LEN) * 8,
+           CSR_READ_4(sc, ALC_SRAM_RX_FIFO_LEN) * 8);
+
+       /* Allocate IRQ resources. */
+       msixc = pci_msix_count(dev);
+       msic = pci_msi_count(dev);
+       if (bootverbose) {
+               device_printf(dev, "MSIX count : %d\n", msixc);
+               device_printf(dev, "MSI count : %d\n", msic);
+       }
+       /* Prefer MSIX over MSI. */
+       if (msix_disable == 0 || msi_disable == 0) {
+               if (msix_disable == 0 && msixc == ALC_MSIX_MESSAGES &&
+                   pci_alloc_msix(dev, &msixc) == 0) {
+                       if (msic == ALC_MSIX_MESSAGES) {
+                               device_printf(dev,
+                                   "Using %d MSIX message(s).\n", msixc);
+                               sc->alc_flags |= ALC_FLAG_MSIX;
+                               sc->alc_irq_spec = alc_irq_spec_msix;
+                       } else
+                               pci_release_msi(dev);
+               }
+               if (msi_disable == 0 && (sc->alc_flags & ALC_FLAG_MSIX) == 0 &&
+                   msic == ALC_MSI_MESSAGES &&
+                   pci_alloc_msi(dev, &msic) == 0) {
+                       if (msic == ALC_MSI_MESSAGES) {
+                               device_printf(dev,
+                                   "Using %d MSI message(s).\n", msic);
+                               sc->alc_flags |= ALC_FLAG_MSI;
+                               sc->alc_irq_spec = alc_irq_spec_msi;
+                       } else
+                               pci_release_msi(dev);
+               }
+       }
+
+       error = bus_alloc_resources(dev, sc->alc_irq_spec, sc->alc_irq);
+       if (error != 0) {
+               device_printf(dev, "cannot allocate IRQ resources.\n");
+               goto fail;
+       }
+
+       /* Create device sysctl node. */
+       alc_sysctl_node(sc);
+
+       if ((error = alc_dma_alloc(sc) != 0))
+               goto fail;
+
+       /* Load station address. */
+       alc_get_macaddr(sc);
+
+       ifp = sc->alc_ifp = if_alloc(IFT_ETHER);
+       if (ifp == NULL) {
+               device_printf(dev, "cannot allocate ifnet structure.\n");
+               error = ENXIO;
+               goto fail;
+       }
+
+       ifp->if_softc = sc;
+       if_initname(ifp, device_get_name(dev), device_get_unit(dev));
+       ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+       ifp->if_ioctl = alc_ioctl;
+       ifp->if_start = alc_start;
+       ifp->if_init = alc_init;
+       ifp->if_snd.ifq_drv_maxlen = ALC_TX_RING_CNT - 1;
+       IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
+       IFQ_SET_READY(&ifp->if_snd);
+       ifp->if_capabilities = IFCAP_TXCSUM | IFCAP_TSO4;
+       ifp->if_hwassist = ALC_CSUM_FEATURES | CSUM_TSO;
+       if (pci_find_extcap(dev, PCIY_PMG, &pmc) == 0)
+               ifp->if_capabilities |= IFCAP_WOL_MAGIC | IFCAP_WOL_MCAST;
+       ifp->if_capenable = ifp->if_capabilities;
+
+       /* Set up MII bus. */
+       if ((error = mii_phy_probe(dev, &sc->alc_miibus, alc_mediachange,
+           alc_mediastatus)) != 0) {
+               device_printf(dev, "no PHY found!\n");
+               goto fail;
+       }
+
+       ether_ifattach(ifp, sc->alc_eaddr);
+
+       /* VLAN capability setup. */
+       ifp->if_capabilities |= IFCAP_VLAN_MTU;
+       ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM;
+       ifp->if_capenable = ifp->if_capabilities;
+       /*
+        * XXX
+        * It seems enabling Tx checksum offloading makes more trouble.
+        * Sometimes the controller does not receive any frames when
+        * Tx checksum offloading is enabled. I'm not sure whether this
+        * is a bug in Tx checksum offloading logic or I got broken
+        * sample boards. To safety, don't enable Tx checksum offloading
+        * by default but give chance to users to toggle it if they know
+        * their controllers work without problems.
+        */
+       ifp->if_capenable &= ~IFCAP_TXCSUM;
+       ifp->if_hwassist &= ~ALC_CSUM_FEATURES;
+
+       /* Tell the upper layer(s) we support long frames. */
+       ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
+
+       /* Create local taskq. */
+       TASK_INIT(&sc->alc_tx_task, 1, alc_tx_task, ifp);
+       sc->alc_tq = taskqueue_create_fast("alc_taskq", M_WAITOK,
+           taskqueue_thread_enqueue, &sc->alc_tq);
+       if (sc->alc_tq == NULL) {
+               device_printf(dev, "could not create taskqueue.\n");
+               ether_ifdetach(ifp);
+               error = ENXIO;
+               goto fail;
+       }
+       taskqueue_start_threads(&sc->alc_tq, 1, PI_NET, "%s taskq",
+           device_get_nameunit(sc->alc_dev));
+
+       if ((sc->alc_flags & ALC_FLAG_MSIX) != 0)
+               msic = ALC_MSIX_MESSAGES;
+       else if ((sc->alc_flags & ALC_FLAG_MSI) != 0)
+               msic = ALC_MSI_MESSAGES;
+       else
+               msic = 1;
+       for (i = 0; i < msic; i++) {
+               error = bus_setup_intr(dev, sc->alc_irq[i],
+                   INTR_TYPE_NET | INTR_MPSAFE, alc_intr, NULL, sc,
+                   &sc->alc_intrhand[i]);
+               if (error != 0)
+                       break;
+       }
+       if (error != 0) {
+               device_printf(dev, "could not set up interrupt handler.\n");
+               taskqueue_free(sc->alc_tq);
+               sc->alc_tq = NULL;
+               ether_ifdetach(ifp);
+               goto fail;
+       }
+
+fail:
+       if (error != 0)
+               alc_detach(dev);
+
+       return (error);
+}
+
+static int
+alc_detach(device_t dev)
+{
+       struct alc_softc *sc;
+       struct ifnet *ifp;
+       int i, msic;
+
+       sc = device_get_softc(dev);
+
+       ifp = sc->alc_ifp;
+       if (device_is_attached(dev)) {
+               ALC_LOCK(sc);
+               sc->alc_flags |= ALC_FLAG_DETACH;
+               alc_stop(sc);
+               ALC_UNLOCK(sc);
+               callout_drain(&sc->alc_tick_ch);
+               taskqueue_drain(sc->alc_tq, &sc->alc_int_task);
+               taskqueue_drain(sc->alc_tq, &sc->alc_tx_task);
+               ether_ifdetach(ifp);
+       }
+
+       if (sc->alc_tq != NULL) {
+               taskqueue_drain(sc->alc_tq, &sc->alc_int_task);
+               taskqueue_free(sc->alc_tq);
+               sc->alc_tq = NULL;
+       }
+
+       if (sc->alc_miibus != NULL) {
+               device_delete_child(dev, sc->alc_miibus);
+               sc->alc_miibus = NULL;
+       }
+       bus_generic_detach(dev);
+       alc_dma_free(sc);
+
+       if (ifp != NULL) {
+               if_free(ifp);
+               sc->alc_ifp = NULL;
+       }
+
+       if ((sc->alc_flags & ALC_FLAG_MSIX) != 0)
+               msic = ALC_MSIX_MESSAGES;
+       else if ((sc->alc_flags & ALC_FLAG_MSI) != 0)
+               msic = ALC_MSI_MESSAGES;
+       else
+               msic = 1;
+       for (i = 0; i < msic; i++) {
+               if (sc->alc_intrhand[i] != NULL) {
+                       bus_teardown_intr(dev, sc->alc_irq[i],
+                           sc->alc_intrhand[i]);
+                       sc->alc_intrhand[i] = NULL;
+               }
+       }
+       if (sc->alc_res[0] != NULL)
+               alc_phy_down(sc);
+       bus_release_resources(dev, sc->alc_irq_spec, sc->alc_irq);
+       if ((sc->alc_flags & (ALC_FLAG_MSI | ALC_FLAG_MSIX)) != 0)
+               pci_release_msi(dev);
+       bus_release_resources(dev, sc->alc_res_spec, sc->alc_res);
+       mtx_destroy(&sc->alc_mtx);
+
+       return (0);
+}
+
+#define        ALC_SYSCTL_STAT_ADD32(c, h, n, p, d)    \
+           SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d)
+#define        ALC_SYSCTL_STAT_ADD64(c, h, n, p, d)    \
+           SYSCTL_ADD_QUAD(c, h, OID_AUTO, n, CTLFLAG_RD, p, d)
+
+static void
+alc_sysctl_node(struct alc_softc *sc)
+{
+       struct sysctl_ctx_list *ctx;
+       struct sysctl_oid_list *child, *parent;
+       struct sysctl_oid *tree;
+       struct alc_hw_stats *stats;
+       int error;
+
+       stats = &sc->alc_stats;
+       ctx = device_get_sysctl_ctx(sc->alc_dev);
+       child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->alc_dev));
+
+       SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "int_rx_mod",
+           CTLTYPE_INT | CTLFLAG_RW, &sc->alc_int_rx_mod, 0,
+           sysctl_hw_alc_int_mod, "I", "alc Rx interrupt moderation");
+       SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "int_tx_mod",
+           CTLTYPE_INT | CTLFLAG_RW, &sc->alc_int_tx_mod, 0,
+           sysctl_hw_alc_int_mod, "I", "alc Tx interrupt moderation");
+       /* Pull in device tunables. */
+       sc->alc_int_rx_mod = ALC_IM_RX_TIMER_DEFAULT;
+       error = resource_int_value(device_get_name(sc->alc_dev),
+           device_get_unit(sc->alc_dev), "int_rx_mod", &sc->alc_int_rx_mod);
+       if (error == 0) {
+               if (sc->alc_int_rx_mod < ALC_IM_TIMER_MIN ||
+                   sc->alc_int_rx_mod > ALC_IM_TIMER_MAX) {
+                       device_printf(sc->alc_dev, "int_rx_mod value out of "
+                           "range; using default: %d\n",
+                           ALC_IM_RX_TIMER_DEFAULT);
+                       sc->alc_int_rx_mod = ALC_IM_RX_TIMER_DEFAULT;
+               }
+       }
+       sc->alc_int_tx_mod = ALC_IM_TX_TIMER_DEFAULT;
+       error = resource_int_value(device_get_name(sc->alc_dev),
+           device_get_unit(sc->alc_dev), "int_tx_mod", &sc->alc_int_tx_mod);
+       if (error == 0) {
+               if (sc->alc_int_tx_mod < ALC_IM_TIMER_MIN ||
+                   sc->alc_int_tx_mod > ALC_IM_TIMER_MAX) {
+                       device_printf(sc->alc_dev, "int_tx_mod value out of "
+                           "range; using default: %d\n",
+                           ALC_IM_TX_TIMER_DEFAULT);
+                       sc->alc_int_tx_mod = ALC_IM_TX_TIMER_DEFAULT;
+               }
+       }
+       SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "process_limit",
+           CTLTYPE_INT | CTLFLAG_RW, &sc->alc_process_limit, 0,
+           sysctl_hw_alc_proc_limit, "I",
+           "max number of Rx events to process");

[... truncated: 4205 lines follow ...]

Other related posts:

  • » [haiku-commits] r34348 - in haiku/trunk/src/add-ons/kernel/drivers/network: . atheros813x atheros813x/dev atheros813x/dev/alc atheros813x/dev/mii - coling