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