Date: Wed, 10 Dec 2008 10:21:54 +0000 (UTC) From: Kip Macy <kmacy@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r185851 - in projects/releng_7_xen: lib/libarchive/test share/man/man4 sys/dev/ae sys/modules/ae Message-ID: <200812101021.mBAALsx5025645@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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@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@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@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 ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200812101021.mBAALsx5025645>