svn commit: r185851 - in projects/releng_7_xen: lib/libarchive/test
share/man/man4 sys/dev/ae sys/modules/ae
Kip Macy
kmacy at FreeBSD.org
Wed Dec 10 02:21:54 PST 2008
Author: kmacy
Date: Wed Dec 10 10:21:54 2008
New Revision: 185851
URL: http://svn.freebsd.org/changeset/base/185851
Log:
push in missed adds
Added:
projects/releng_7_xen/lib/libarchive/test/test_acl_freebsd.c (contents, props changed)
projects/releng_7_xen/share/man/man4/ae.4 (contents, props changed)
projects/releng_7_xen/sys/dev/ae/if_ae.c (contents, props changed)
projects/releng_7_xen/sys/dev/ae/if_aereg.h (contents, props changed)
projects/releng_7_xen/sys/dev/ae/if_aevar.h (contents, props changed)
projects/releng_7_xen/sys/modules/ae/Makefile (contents, props changed)
Added: projects/releng_7_xen/lib/libarchive/test/test_acl_freebsd.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/releng_7_xen/lib/libarchive/test/test_acl_freebsd.c Wed Dec 10 10:21:54 2008 (r185851)
@@ -0,0 +1,243 @@
+/*-
+ * Copyright (c) 2003-2008 Tim Kientzle
+ * 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, 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(S) ``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(S) 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 "test.h"
+__FBSDID("$FreeBSD$");
+
+#if defined(__FreeBSD__) && __FreeBSD__ > 4
+#include <sys/acl.h>
+
+struct myacl_t {
+ int type; /* Type of ACL: "access" or "default" */
+ int permset; /* Permissions for this class of users. */
+ int tag; /* Owner, User, Owning group, group, other, etc. */
+ int qual; /* GID or UID of user/group, depending on tag. */
+ const char *name; /* Name of user/group, depending on tag. */
+};
+
+static struct myacl_t acls2[] = {
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE | ARCHIVE_ENTRY_ACL_READ,
+ ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
+ ARCHIVE_ENTRY_ACL_USER, 77, "user77" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0,
+ ARCHIVE_ENTRY_ACL_USER, 78, "user78" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
+ ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0007,
+ ARCHIVE_ENTRY_ACL_GROUP, 78, "group78" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_WRITE | ARCHIVE_ENTRY_ACL_EXECUTE,
+ ARCHIVE_ENTRY_ACL_OTHER, -1, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_WRITE | ARCHIVE_ENTRY_ACL_READ | ARCHIVE_ENTRY_ACL_EXECUTE,
+ ARCHIVE_ENTRY_ACL_MASK, -1, "" },
+ { 0, 0, 0, 0, NULL }
+};
+
+static void
+set_acls(struct archive_entry *ae, struct myacl_t *acls)
+{
+ int i;
+
+ archive_entry_acl_clear(ae);
+ for (i = 0; acls[i].name != NULL; i++) {
+ archive_entry_acl_add_entry(ae,
+ acls[i].type, acls[i].permset, acls[i].tag, acls[i].qual,
+ acls[i].name);
+ }
+}
+
+static int
+acl_match(acl_entry_t aclent, struct myacl_t *myacl)
+{
+ acl_tag_t tag_type;
+ acl_permset_t opaque_ps;
+ int permset = 0;
+
+ acl_get_tag_type(aclent, &tag_type);
+
+ /* translate the silly opaque permset to a bitmap */
+ acl_get_permset(aclent, &opaque_ps);
+ if (acl_get_perm_np(opaque_ps, ACL_EXECUTE))
+ permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
+ if (acl_get_perm_np(opaque_ps, ACL_WRITE))
+ permset |= ARCHIVE_ENTRY_ACL_WRITE;
+ if (acl_get_perm_np(opaque_ps, ACL_READ))
+ permset |= ARCHIVE_ENTRY_ACL_READ;
+
+ if (permset != myacl->permset)
+ return (0);
+
+ switch (tag_type) {
+ case ACL_USER_OBJ:
+ if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ) return (0);
+ break;
+ case ACL_USER:
+ if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
+ return (0);
+ if ((uid_t)myacl->qual != *(uid_t *)acl_get_qualifier(aclent))
+ return (0);
+ break;
+ case ACL_GROUP_OBJ:
+ if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ) return (0);
+ break;
+ case ACL_GROUP:
+ if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
+ return (0);
+ if ((gid_t)myacl->qual != *(gid_t *)acl_get_qualifier(aclent))
+ return (0);
+ break;
+ case ACL_MASK:
+ if (myacl->tag != ARCHIVE_ENTRY_ACL_MASK) return (0);
+ break;
+ case ACL_OTHER:
+ if (myacl->tag != ARCHIVE_ENTRY_ACL_OTHER) return (0);
+ break;
+ }
+ return (1);
+}
+
+static void
+compare_acls(acl_t acl, struct myacl_t *myacls)
+{
+ int *marker;
+ int entry_id = ACL_FIRST_ENTRY;
+ int matched;
+ int i, n;
+ acl_entry_t acl_entry;
+
+ /* Count ACL entries in myacls array and allocate an indirect array. */
+ for (n = 0; myacls[n].name != NULL; ++n)
+ continue;
+ marker = malloc(sizeof(marker[0]) * n);
+ for (i = 0; i < n; i++)
+ marker[i] = i;
+
+ /*
+ * Iterate over acls in system acl object, try to match each
+ * one with an item in the myacls array.
+ */
+ while (1 == acl_get_entry(acl, entry_id, &acl_entry)) {
+ /* After the first time... */
+ entry_id = ACL_NEXT_ENTRY;
+
+ /* Search for a matching entry (tag and qualifier) */
+ for (i = 0, matched = 0; i < n && !matched; i++) {
+ if (acl_match(acl_entry, &myacls[marker[i]])) {
+ /* We found a match; remove it. */
+ marker[i] = marker[n - 1];
+ n--;
+ matched = 1;
+ }
+ }
+
+ /* TODO: Print out more details in this case. */
+ failure("ACL entry on file that shouldn't be there");
+ assert(matched == 1);
+ }
+
+ /* Dump entries in the myacls array that weren't in the system acl. */
+ for (i = 0; i < n; ++i) {
+ failure(" ACL entry missing from file: "
+ "type=%d,permset=%d,tag=%d,qual=%d,name=``%s''\n",
+ myacls[marker[i]].type, myacls[marker[i]].permset,
+ myacls[marker[i]].tag, myacls[marker[i]].qual,
+ myacls[marker[i]].name);
+ assert(0); /* Record this as a failure. */
+ }
+ free(marker);
+}
+
+#endif
+
+
+/*
+ * Verify ACL restore-to-disk. This test is FreeBSD-specific.
+ */
+
+DEFINE_TEST(test_acl_freebsd)
+{
+#if !defined(__FreeBSD__)
+ skipping("FreeBSD-specific ACL restore test");
+#elif __FreeBSD__ < 5
+ skipping("ACL restore supported only on FreeBSD 5.0 and later");
+#else
+ struct stat st;
+ struct archive *a;
+ struct archive_entry *ae;
+ int n, fd;
+ acl_t acl;
+
+ /*
+ * First, do a quick manual set/read of ACL data to
+ * verify that the local filesystem does support ACLs.
+ * If it doesn't, we'll simply skip the remaining tests.
+ */
+ acl = acl_from_text("u::rwx,u:1:rw,g::rwx,g:15:rx,o::rwx,m::rwx");
+ assert((void *)acl != NULL);
+ /* Create a test file and try to set an ACL on it. */
+ fd = open("pretest", O_WRONLY | O_CREAT | O_EXCL, 0777);
+ failure("Could not create test file?!");
+ n = -1;
+ if (assert(fd >= 0)) {
+ n = acl_set_fd(fd, acl);
+ failure("acl_set_fd(): errno = %d (%s)",
+ errno, strerror(errno));
+ assertEqualInt(0, n);
+ close(fd);
+ }
+
+ if (fd < 0 || n != 0) {
+ skipping("ACL tests require that ACL support be enabled on the filesystem");
+ return;
+ }
+
+ /* Create a write-to-disk object. */
+ assert(NULL != (a = archive_write_disk_new()));
+ archive_write_disk_set_options(a,
+ ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL);
+
+ /* Populate an archive entry with some metadata, including ACL info */
+ ae = archive_entry_new();
+ assert(ae != NULL);
+ archive_entry_set_pathname(ae, "test0");
+ archive_entry_set_mtime(ae, 123456, 7890);
+ archive_entry_set_size(ae, 0);
+ set_acls(ae, acls2);
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
+ archive_entry_free(ae);
+
+ /* Close the archive. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_write_finish(a));
+
+ /* Verify the data on disk. */
+ assertEqualInt(0, stat("test0", &st));
+ assertEqualInt(st.st_mtime, 123456);
+ acl = acl_get_file("test0", ACL_TYPE_ACCESS);
+ assert(acl != (acl_t)NULL);
+ compare_acls(acl, acls2);
+#endif
+}
Added: projects/releng_7_xen/share/man/man4/ae.4
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/releng_7_xen/share/man/man4/ae.4 Wed Dec 10 10:21:54 2008 (r185851)
@@ -0,0 +1,153 @@
+.\" Copyright (c) 2008 Stanislav Sedov <stas at FreeBSD.org>
+.\" 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, 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$
+.\"
+.Dd October 4, 2008
+.Dt AE 4
+.Os
+.Sh NAME
+.Nm ae
+.Nd "Attansic/Atheros L2 FastEthernet controller driver"
+.Sh SYNOPSIS
+To compile this driver into the kernel, place the following lines in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device miibus"
+.Cd "device ae"
+.Ed
+.Pp
+Alternatively, to load the driver as a
+module at boot time, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset -indent
+if_ae_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+device driver provides support for Attansic/Atheros L2 PCIe FastEthernet
+controllers.
+.Pp
+The controller supports hardware Ethernet checksum processing, hardware
+VLAN tag stripping/insertion and an interrupt moderation mechanism.
+Attansic L2 also features a 64-bit multicast hash filter.
+.Pp
+The
+.Nm
+driver supports the following media types:
+.Bl -tag -width ".Cm 10baseT/UTP"
+.It Cm autoselect
+Enable autoselection of the media type and options.
+The user can manually override the autoselected mode by
+adding media options to
+.Xr rc.conf 5 .
+.It Cm 10baseT/UTP
+Select 10Mbps operation.
+.It Cm 100baseTX
+Set 100Mbps (FastEthernet) operation.
+.El
+.Pp
+The
+.Nm
+driver provides support for the following media options:
+.Bl -tag -width ".Cm full-duplex"
+.It Cm full-duplex
+Force full duplex operation.
+.It Cm half-duplex
+Force half duplex operation.
+.El
+.Pp
+For more information on configuring this device, see
+.Xr ifconfig 8 .
+.Sh HARDWARE
+The
+.Nm
+driver supports Attansic/Atheros L2 PCIe FastEthernet controllers, and
+is known to support the following hardware:
+.Pp
+.Bl -bullet -compact
+.It
+ASUS EeePC 701
+.It
+ASUS EeePC 900
+.El
+.Pp
+Other hardware may or may not work with this driver.
+.Sh LOADER TUNABLES
+Tunables can be set at the
+.Xr loader 8
+prompt before booting the kernel or stored in
+.Xr loader.conf 5 .
+.Bl -tag -width "xxxxxx"
+.It Va hw.ae.msi_disable
+This tunable disables MSI support on the Ethernet hardware.
+The default value is 0.
+.El
+.Sh SYSCTL VARIABLES
+The
+.Nm
+driver collects a number of useful MAC counter during the work.
+The statistics is available via the
+.Va dev.ae.%d.stats
+.Xr sysctl 8
+tree, where %d corresponds to the controller number.
+.Sh DIAGNOSTICS
+.Bl -diag
+.It "ae%d: watchdog timeout."
+The device has stopped responding to the network, or there is a problem with
+the network connection (cable).
+.It "ae%d: reset timeout."
+The card reset operation has been timed out.
+.It "ae%d: Generating random ethernet address."
+No valid ethernet address was found neither in the controller registers not in
+NVRAM.
+Random locally administered address with ASUS OUI identifier will be used
+instead.
+.El
+.Sh SEE ALSO
+.Xr altq 4 ,
+.Xr arp 4 ,
+.Xr miibus 4 ,
+.Xr netintro 4 ,
+.Xr ng_ether 4 ,
+.Xr vlan 4 ,
+.Xr ifconfig 8
+.Sh BUGS
+The Attansic L2 FastEthernet contoller supports DMA but do not use a descriptor
+based transfer mechanism via scatter-gather DMA.
+Thus the data should be copied to/from the controller memory on each
+transmit/receive.
+Furthermore, a lot of data alignment restrictions apply.
+This may introduce a high CPU load on systems with heavy network activity.
+Luckily enough this should not be a problem on modern hardware as L2 does
+not support speeds faster than 100Mbps.
+.Sh HISTORY
+The
+.Nm
+driver and this manual page was written by
+.An Stanislav Sedov
+.Aq stas at FreeBSD.org .
+It first appeared in
+.Fx 7.1 .
Added: projects/releng_7_xen/sys/dev/ae/if_ae.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/releng_7_xen/sys/dev/ae/if_ae.c Wed Dec 10 10:21:54 2008 (r185851)
@@ -0,0 +1,2223 @@
+/*-
+ * Copyright (c) 2008 Stanislav Sedov <stas at FreeBSD.org>.
+ * 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, 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 ``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 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 Attansic Technology Corp. L2 FastEthernet adapter.
+ *
+ * This driver is heavily based on age(4) Attansic L1 driver by Pyun YongHyeon.
+ */
+
+#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/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/rman.h>
+#include <sys/module.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_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/bus.h>
+
+#include "miibus_if.h"
+
+#include "if_aereg.h"
+#include "if_aevar.h"
+
+/*
+ * Devices supported by this driver.
+ */
+static struct ae_dev {
+ uint16_t vendorid;
+ uint16_t deviceid;
+ const char *name;
+} ae_devs[] = {
+ { VENDORID_ATTANSIC, DEVICEID_ATTANSIC_L2,
+ "Attansic Technology Corp, L2 FastEthernet" },
+};
+#define AE_DEVS_COUNT (sizeof(ae_devs) / sizeof(*ae_devs))
+
+static struct resource_spec ae_res_spec_mem[] = {
+ { SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE },
+ { -1, 0, 0 }
+};
+static struct resource_spec ae_res_spec_irq[] = {
+ { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE },
+ { -1, 0, 0 }
+};
+static struct resource_spec ae_res_spec_msi[] = {
+ { SYS_RES_IRQ, 1, RF_ACTIVE },
+ { -1, 0, 0 }
+};
+
+static int ae_probe(device_t dev);
+static int ae_attach(device_t dev);
+static void ae_pcie_init(ae_softc_t *sc);
+static void ae_phy_reset(ae_softc_t *sc);
+static void ae_phy_init(ae_softc_t *sc);
+static int ae_reset(ae_softc_t *sc);
+static void ae_init(void *arg);
+static int ae_init_locked(ae_softc_t *sc);
+static unsigned int ae_detach(device_t dev);
+static int ae_miibus_readreg(device_t dev, int phy, int reg);
+static int ae_miibus_writereg(device_t dev, int phy, int reg, int val);
+static void ae_miibus_statchg(device_t dev);
+static void ae_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr);
+static int ae_mediachange(struct ifnet *ifp);
+static void ae_retrieve_address(ae_softc_t *sc);
+static void ae_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs,
+ int error);
+static int ae_alloc_rings(ae_softc_t *sc);
+static void ae_dma_free(ae_softc_t *sc);
+static int ae_shutdown(device_t dev);
+static int ae_suspend(device_t dev);
+static void ae_powersave_disable(ae_softc_t *sc);
+static void ae_powersave_enable(ae_softc_t *sc);
+static int ae_resume(device_t dev);
+static unsigned int ae_tx_avail_size(ae_softc_t *sc);
+static int ae_encap(ae_softc_t *sc, struct mbuf **m_head);
+static void ae_start(struct ifnet *ifp);
+static void ae_link_task(void *arg, int pending);
+static void ae_stop_rxmac(ae_softc_t *sc);
+static void ae_stop_txmac(ae_softc_t *sc);
+static void ae_tx_task(void *arg, int pending);
+static void ae_mac_config(ae_softc_t *sc);
+static int ae_intr(void *arg);
+static void ae_int_task(void *arg, int pending);
+static void ae_tx_intr(ae_softc_t *sc);
+static int ae_rxeof(ae_softc_t *sc, ae_rxd_t *rxd);
+static void ae_rx_intr(ae_softc_t *sc);
+static void ae_watchdog(ae_softc_t *sc);
+static void ae_tick(void *arg);
+static void ae_rxfilter(ae_softc_t *sc);
+static void ae_rxvlan(ae_softc_t *sc);
+static int ae_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
+static void ae_stop(ae_softc_t *sc);
+static int ae_check_eeprom_present(ae_softc_t *sc, int *vpdc);
+static int ae_vpd_read_word(ae_softc_t *sc, int reg, uint32_t *word);
+static int ae_get_vpd_eaddr(ae_softc_t *sc, uint32_t *eaddr);
+static int ae_get_reg_eaddr(ae_softc_t *sc, uint32_t *eaddr);
+static void ae_update_stats_rx(uint16_t flags, ae_stats_t *stats);
+static void ae_update_stats_tx(uint16_t flags, ae_stats_t *stats);
+static void ae_init_tunables(ae_softc_t *sc);
+
+static device_method_t ae_methods[] = {
+ /* Device interface. */
+ DEVMETHOD(device_probe, ae_probe),
+ DEVMETHOD(device_attach, ae_attach),
+ DEVMETHOD(device_detach, ae_detach),
+ DEVMETHOD(device_shutdown, ae_shutdown),
+ DEVMETHOD(device_suspend, ae_suspend),
+ DEVMETHOD(device_resume, ae_resume),
+
+ /* MII interface. */
+ DEVMETHOD(miibus_readreg, ae_miibus_readreg),
+ DEVMETHOD(miibus_writereg, ae_miibus_writereg),
+ DEVMETHOD(miibus_statchg, ae_miibus_statchg),
+
+ { NULL, NULL }
+};
+static driver_t ae_driver = {
+ "ae",
+ ae_methods,
+ sizeof(ae_softc_t)
+};
+static devclass_t ae_devclass;
+
+DRIVER_MODULE(ae, pci, ae_driver, ae_devclass, 0, 0);
+DRIVER_MODULE(miibus, ae, miibus_driver, miibus_devclass, 0, 0);
+MODULE_DEPEND(ae, pci, 1, 1, 1);
+MODULE_DEPEND(ae, ether, 1, 1, 1);
+MODULE_DEPEND(ae, miibus, 1, 1, 1);
+
+/*
+ * Tunables.
+ */
+static int msi_disable = 0;
+TUNABLE_INT("hw.ae.msi_disable", &msi_disable);
+
+#define AE_READ_4(sc, reg) \
+ bus_read_4((sc)->mem[0], (reg))
+#define AE_READ_2(sc, reg) \
+ bus_read_2((sc)->mem[0], (reg))
+#define AE_READ_1(sc, reg) \
+ bus_read_1((sc)->mem[0], (reg))
+#define AE_WRITE_4(sc, reg, val) \
+ bus_write_4((sc)->mem[0], (reg), (val))
+#define AE_WRITE_2(sc, reg, val) \
+ bus_write_2((sc)->mem[0], (reg), (val))
+#define AE_WRITE_1(sc, reg, val) \
+ bus_write_1((sc)->mem[0], (reg), (val))
+#define AE_PHY_READ(sc, reg) \
+ ae_miibus_readreg(sc->dev, 0, reg)
+#define AE_PHY_WRITE(sc, reg, val) \
+ ae_miibus_writereg(sc->dev, 0, reg, val)
+#define AE_CHECK_EADDR_VALID(eaddr) \
+ ((eaddr[0] == 0 && eaddr[1] == 0) || \
+ (eaddr[0] == 0xffffffff && eaddr[1] == 0xffff))
+#define AE_RXD_VLAN(vtag) \
+ (((vtag) >> 4) | (((vtag) & 0x07) << 13) | (((vtag) & 0x08) << 9))
+#define AE_TXD_VLAN(vtag) \
+ (((vtag) << 4) | (((vtag) >> 13) & 0x07) | (((vtag) >> 9) & 0x08))
+
+/*
+ * ae statistics.
+ */
+#define STATS_ENTRY(node, desc, field) \
+ { node, desc, offsetof(struct ae_stats, field) }
+struct {
+ const char *node;
+ const char *desc;
+ intptr_t offset;
+} ae_stats_tx[] = {
+ STATS_ENTRY("bcast", "broadcast frames", tx_bcast),
+ STATS_ENTRY("mcast", "multicast frames", tx_mcast),
+ STATS_ENTRY("pause", "PAUSE frames", tx_pause),
+ STATS_ENTRY("control", "control frames", tx_ctrl),
+ STATS_ENTRY("defers", "deferrals occuried", tx_defer),
+ STATS_ENTRY("exc_defers", "excessive deferrals occuried", tx_excdefer),
+ STATS_ENTRY("singlecols", "single collisions occuried", tx_singlecol),
+ STATS_ENTRY("multicols", "multiple collisions occuried", tx_multicol),
+ STATS_ENTRY("latecols", "late collisions occuried", tx_latecol),
+ STATS_ENTRY("aborts", "transmit aborts due collisions", tx_abortcol),
+ STATS_ENTRY("underruns", "Tx FIFO underruns", tx_underrun)
+}, ae_stats_rx[] = {
+ STATS_ENTRY("bcast", "broadcast frames", rx_bcast),
+ STATS_ENTRY("mcast", "multicast frames", rx_mcast),
+ STATS_ENTRY("pause", "PAUSE frames", rx_pause),
+ STATS_ENTRY("control", "control frames", rx_ctrl),
+ STATS_ENTRY("crc_errors", "frames with CRC errors", rx_crcerr),
+ STATS_ENTRY("code_errors", "frames with invalid opcode", rx_codeerr),
+ STATS_ENTRY("runt", "runt frames", rx_runt),
+ STATS_ENTRY("frag", "fragmented frames", rx_frag),
+ STATS_ENTRY("align_errors", "frames with alignment errors", rx_align),
+ STATS_ENTRY("truncated", "frames truncated due to Rx FIFO inderrun",
+ rx_trunc)
+};
+#define AE_STATS_RX_LEN (sizeof(ae_stats_rx) / sizeof(*ae_stats_rx))
+#define AE_STATS_TX_LEN (sizeof(ae_stats_tx) / sizeof(*ae_stats_tx))
+
+static int
+ae_probe(device_t dev)
+{
+ uint16_t deviceid, vendorid;
+ int i;
+
+ vendorid = pci_get_vendor(dev);
+ deviceid = pci_get_device(dev);
+
+ /*
+ * Search through the list of supported devs for matching one.
+ */
+ for (i = 0; i < AE_DEVS_COUNT; i++) {
+ if (vendorid == ae_devs[i].vendorid &&
+ deviceid == ae_devs[i].deviceid) {
+ device_set_desc(dev, ae_devs[i].name);
+ return (BUS_PROBE_DEFAULT);
+ }
+ }
+ return (ENXIO);
+}
+
+static int
+ae_attach(device_t dev)
+{
+ ae_softc_t *sc;
+ struct ifnet *ifp;
+ uint8_t chiprev;
+ uint32_t pcirev;
+ int nmsi, pmc;
+ int error;
+
+ sc = device_get_softc(dev); /* Automatically allocated and zeroed
+ on attach. */
+ KASSERT(sc != NULL, ("[ae, %d]: sc is NULL", __LINE__));
+ sc->dev = dev;
+
+ /*
+ * Initialize mutexes and tasks.
+ */
+ mtx_init(&sc->mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF);
+ callout_init_mtx(&sc->tick_ch, &sc->mtx, 0);
+ TASK_INIT(&sc->int_task, 0, ae_int_task, sc);
+ TASK_INIT(&sc->link_task, 0, ae_link_task, sc);
+
+ pci_enable_busmaster(dev); /* Enable bus mastering. */
+
+ sc->spec_mem = ae_res_spec_mem;
+
+ /*
+ * Allocate memory-mapped registers.
+ */
+ error = bus_alloc_resources(dev, sc->spec_mem, sc->mem);
+ if (error != 0) {
+ device_printf(dev, "could not allocate memory resources.\n");
+ sc->spec_mem = NULL;
+ goto fail;
+ }
+
+ /*
+ * Retrieve PCI and chip revisions.
+ */
+ pcirev = pci_get_revid(dev);
+ chiprev = (AE_READ_4(sc, AE_MASTER_REG) >> AE_MASTER_REVNUM_SHIFT) &
+ AE_MASTER_REVNUM_MASK;
+ if (bootverbose) {
+ device_printf(dev, "pci device revision: %#04x\n", pcirev);
+ device_printf(dev, "chip id: %#02x\n", chiprev);
+ }
+ nmsi = pci_msi_count(dev);
+ if (bootverbose)
+ device_printf(dev, "MSI count: %d.\n", nmsi);
+
+ /*
+ * Allocate interrupt resources.
+ */
+ if (msi_disable == 0 && nmsi == 1) {
+ error = pci_alloc_msi(dev, &nmsi);
+ if (error == 0) {
+ device_printf(dev, "Using MSI messages.\n");
+ sc->spec_irq = ae_res_spec_msi;
+ error = bus_alloc_resources(dev, sc->spec_irq, sc->irq);
+ if (error != 0) {
+ device_printf(dev, "MSI allocation failed.\n");
+ sc->spec_irq = NULL;
+ pci_release_msi(dev);
+ } else {
+ sc->flags |= AE_FLAG_MSI;
+ }
+ }
+ }
+ if (sc->spec_irq == NULL) {
+ sc->spec_irq = ae_res_spec_irq;
+ error = bus_alloc_resources(dev, sc->spec_irq, sc->irq);
+ if (error != 0) {
+ device_printf(dev, "could not allocate IRQ resources.\n");
+ sc->spec_irq = NULL;
+ goto fail;
+ }
+ }
+
+ ae_init_tunables(sc);
+
+ ae_phy_reset(sc); /* Reset PHY. */
+ error = ae_reset(sc); /* Reset the controller itself. */
+ if (error != 0)
+ goto fail;
+
+ ae_pcie_init(sc);
+
+ ae_retrieve_address(sc); /* Load MAC address. */
+
+ error = ae_alloc_rings(sc); /* Allocate ring buffers. */
+ if (error != 0)
+ goto fail;
+
+ /* Set default PHY address. */
+ sc->phyaddr = AE_PHYADDR_DEFAULT;
+
+ ifp = sc->ifp = if_alloc(IFT_ETHER);
+ if (ifp == NULL) {
+ device_printf(dev, "could not allocate ifnet structure.\n");
+ error = ENXIO;
+ }
+
+ 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 = ae_ioctl;
+ ifp->if_start = ae_start;
+ ifp->if_init = ae_init;
+ ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING;
+ ifp->if_hwassist = 0;
+ ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
+ IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
+ IFQ_SET_READY(&ifp->if_snd);
+ if (pci_find_extcap(dev, PCIY_PMG, &pmc) == 0)
+ sc->flags |= AE_FLAG_PMG;
+ ifp->if_capenable = ifp->if_capabilities;
+
+ /*
+ * Configure and attach MII bus.
+ */
+ error = mii_phy_probe(dev, &sc->miibus, ae_mediachange,
+ ae_mediastatus);
+ if (error != 0) {
+ device_printf(dev, "no PHY found.\n");
+ goto fail;
+ }
+
+ ether_ifattach(ifp, sc->eaddr);
+ /* Tell the upper layer(s) we support long frames. */
+ ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
+
+ /*
+ * Create and run all helper tasks.
+ */
+ TASK_INIT(&sc->tx_task, 1, ae_tx_task, ifp);
+ sc->tq = taskqueue_create_fast("ae_taskq", M_WAITOK,
+ taskqueue_thread_enqueue, &sc->tq);
+ if (sc->tq == NULL) {
+ device_printf(dev, "could not create taskqueue.\n");
+ ether_ifdetach(ifp);
+ error = ENXIO;
+ goto fail;
+ }
+ taskqueue_start_threads(&sc->tq, 1, PI_NET, "%s taskq",
+ device_get_nameunit(sc->dev));
+
+ /*
+ * Configure interrupt handlers.
+ */
+ error = bus_setup_intr(dev, sc->irq[0], INTR_TYPE_NET | INTR_MPSAFE,
+ ae_intr, NULL, sc, &sc->intrhand);
+ if (error != 0) {
+ device_printf(dev, "could not set up interrupt handler.\n");
+ taskqueue_free(sc->tq);
+ sc->tq = NULL;
+ ether_ifdetach(ifp);
+ goto fail;
+ }
+
+fail:
+ if (error != 0)
+ ae_detach(dev);
+
+ return (error);
+}
+
+static void
+ae_init_tunables(ae_softc_t *sc)
+{
+ struct sysctl_ctx_list *ctx;
+ struct sysctl_oid *root, *stats, *stats_rx, *stats_tx;
+ struct ae_stats *ae_stats;
+ unsigned int i;
+
+ KASSERT(sc != NULL, ("[ae, %d]: sc is NULL", __LINE__));
+ ae_stats = &sc->stats;
+
+ ctx = device_get_sysctl_ctx(sc->dev);
+ root = device_get_sysctl_tree(sc->dev);
+ stats = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(root), OID_AUTO, "stats",
+ CTLFLAG_RD, NULL, "ae statistics");
+
+ /*
+ * Receiver statistcics.
+ */
+ stats_rx = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, "rx",
+ CTLFLAG_RD, NULL, "Rx MAC statistics");
+ for (i = 0; i < AE_STATS_RX_LEN; i++)
+ SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(stats_rx), OID_AUTO,
+ ae_stats_rx[i].node, CTLFLAG_RD, (char *)ae_stats +
+ ae_stats_rx[i].offset, 0, ae_stats_rx[i].desc);
+
+ /*
+ * Receiver statistcics.
+ */
+ stats_tx = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, "tx",
+ CTLFLAG_RD, NULL, "Tx MAC statistics");
+ for (i = 0; i < AE_STATS_TX_LEN; i++)
+ SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(stats_tx), OID_AUTO,
+ ae_stats_tx[i].node, CTLFLAG_RD, (char *)ae_stats +
+ ae_stats_tx[i].offset, 0, ae_stats_tx[i].desc);
+}
+
+static void
+ae_pcie_init(ae_softc_t *sc)
+{
+
+ AE_WRITE_4(sc, AE_PCIE_LTSSM_TESTMODE_REG, AE_PCIE_LTSSM_TESTMODE_DEFAULT);
+ AE_WRITE_4(sc, AE_PCIE_DLL_TX_CTRL_REG, AE_PCIE_DLL_TX_CTRL_DEFAULT);
+}
+
+static void
+ae_phy_reset(ae_softc_t *sc)
+{
+
+ AE_WRITE_4(sc, AE_PHY_ENABLE_REG, AE_PHY_ENABLE);
+ DELAY(1000); /* XXX: pause(9) ? */
+}
+
+static int
+ae_reset(ae_softc_t *sc)
+{
+ int i;
+
+ /*
+ * Issue a soft reset.
+ */
+ AE_WRITE_4(sc, AE_MASTER_REG, AE_MASTER_SOFT_RESET);
+ bus_barrier(sc->mem[0], AE_MASTER_REG, 4,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+
+ /*
+ * Wait for reset to complete.
+ */
+ for (i = 0; i < AE_RESET_TIMEOUT; i++) {
+ if ((AE_READ_4(sc, AE_MASTER_REG) & AE_MASTER_SOFT_RESET) == 0)
+ break;
+ DELAY(10);
+ }
+ if (i == AE_RESET_TIMEOUT) {
+ device_printf(sc->dev, "reset timeout.\n");
+ return (ENXIO);
+ }
+
+ /*
+ * Wait for everything to enter idle state.
+ */
+ for (i = 0; i < AE_IDLE_TIMEOUT; i++) {
+ if (AE_READ_4(sc, AE_IDLE_REG) == 0)
+ break;
+ DELAY(100);
+ }
+ if (i == AE_IDLE_TIMEOUT) {
+ device_printf(sc->dev, "could not enter idle state.\n");
+ return (ENXIO);
+ }
+ return (0);
+}
+
+static void
+ae_init(void *arg)
+{
+ ae_softc_t *sc;
+
+ sc = (ae_softc_t *)arg;
+ AE_LOCK(sc);
+ ae_init_locked(sc);
+ AE_UNLOCK(sc);
+}
+
+static void
+ae_phy_init(ae_softc_t *sc)
+{
+
+ /*
+ * Enable link status change interrupt.
+ * XXX magic numbers.
+ */
+#ifdef notyet
+ AE_PHY_WRITE(sc, 18, 0xc00);
+#endif
+}
+
+static int
+ae_init_locked(ae_softc_t *sc)
+{
+ struct ifnet *ifp;
+ struct mii_data *mii;
+ uint8_t eaddr[ETHER_ADDR_LEN];
+ uint32_t val;
+ bus_addr_t addr;
+
+ AE_LOCK_ASSERT(sc);
+
+ ifp = sc->ifp;
+ mii = device_get_softc(sc->miibus);
+
+ ae_stop(sc);
+ ae_reset(sc);
+ ae_pcie_init(sc); /* Initialize PCIE stuff. */
+ ae_phy_init(sc);
+ ae_powersave_disable(sc);
+
+ /*
+ * Clear and disable interrupts.
+ */
+ AE_WRITE_4(sc, AE_ISR_REG, 0xffffffff);
+
+ /*
+ * Set the MAC address.
+ */
+ bcopy(IF_LLADDR(ifp), eaddr, ETHER_ADDR_LEN);
+ val = eaddr[2] << 24 | eaddr[3] << 16 | eaddr[4] << 8 | eaddr[5];
+ AE_WRITE_4(sc, AE_EADDR0_REG, val);
+ val = eaddr[0] << 8 | eaddr[1];
+ AE_WRITE_4(sc, AE_EADDR1_REG, val);
+
+ /*
+ * Set ring buffers base addresses.
+ */
+ addr = sc->dma_rxd_busaddr;
+ AE_WRITE_4(sc, AE_DESC_ADDR_HI_REG, BUS_ADDR_HI(addr));
+ AE_WRITE_4(sc, AE_RXD_ADDR_LO_REG, BUS_ADDR_LO(addr));
+ addr = sc->dma_txd_busaddr;
+ AE_WRITE_4(sc, AE_TXD_ADDR_LO_REG, BUS_ADDR_LO(addr));
+ addr = sc->dma_txs_busaddr;
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-projects
mailing list