Current-Users archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Updating axe(4) for AX88178 and AX88772 chips
I acquired an AX88772-based adapter today, and discovered that our
axe(4) driver was rather out of date and does not support either of the
newer ASIX chips. NetBSD's driver was ported from OpenBSD about 5 1/2
years ago and hasn't been re-synched since.
So, I've merged all of the OpenBSD changes into -current. The resulting
diffs are attached. I've tested in on my system and it works quite
well.
There apparently has been a previous effort at updating this driver by
FUKAUMI Naoki (see [1] for details). His attempt appears to be based on
the same OpenBSD rev. There's a separate thread on tech-net@ to help
decide which update, if either, should be merged into NetBSD. In the
meantime, I'd appreciate any feedback or test results for my version.
[1] http://mail-index.netbsd.org/tech-net/2010/04/18/msg002049.html for
-------------------------------------------------------------------------
| Paul Goyette | PGP Key fingerprint: | E-mail addresses: |
| Customer Service | FA29 0E3B 35AF E8AE 6651 | paul at whooppee.com |
| Network Engineer | 0786 F758 55DE 53BA 7731 | pgoyette at juniper.net |
| Kernel Developer | | pgoyette at netbsd.org |
-------------------------------------------------------------------------
Index: if_axe.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_axe.c,v
retrieving revision 1.32
diff -u -p -r1.32 if_axe.c
--- if_axe.c 5 Apr 2010 07:21:48 -0000 1.32
+++ if_axe.c 13 Jun 2010 08:40:37 -0000
@@ -1,4 +1,21 @@
/* $NetBSD: if_axe.c,v 1.32 2010/04/05 07:21:48 joerg Exp $ */
+/* $OpenBSD: if_axe.c,v 1.96 2010/01/09 05:33:08 jsg Exp $ */
+
+/*
+ * Copyright (c) 2005, 2006, 2007 Jonathan Gray <jsg%openbsd.org@localhost>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
/*
* Copyright (c) 1997, 1998, 1999, 2000-2003
@@ -97,6 +114,8 @@ __KERNEL_RCSID(0, "$NetBSD: if_axe.c,v 1
#include <sys/rnd.h>
#endif
+#include <machine/bus.h>
+
#include <net/if.h>
#if defined(__NetBSD__)
#include <net/if_arp.h>
@@ -130,6 +149,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_axe.c,v 1
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdivar.h>
#include <dev/usb/usbdi_util.h>
#include <dev/usb/usbdevs.h>
@@ -144,18 +164,44 @@ int axedebug = 0;
#define DPRINTFN(n,x)
#endif
+#ifdef __NetBSD__
+ #define letoh16 htole16
+ #define letoh32 htole32
+#endif
+
/*
* Various supported device vendors/products.
*/
Static const struct axe_type axe_devs[] = {
+ { { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_UFE2000}, 0 },
+ { { USB_VENDOR_ACERCM, USB_PRODUCT_ACERCM_EP1427X2}, 0 },
+ { { USB_VENDOR_APPLE, USB_PRODUCT_APPLE_ETHERNET }, AX772 },
{ { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88172}, 0 },
+ { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772}, AX772 },
+ { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772A}, AX772 },
+ { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88178}, AX178 },
+ { { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC210T}, 0 },
+ { { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D5055 }, AX178 },
+ { { USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USB2AR}, 0},
+ { { USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_USB200MV2},
AX772 },
{ { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB2_TX }, 0},
{ { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100}, 0 },
+ { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100B1 }, AX772 },
+ { { USB_VENDOR_GOODWAY, USB_PRODUCT_GOODWAY_GWUSB2E}, 0 },
+ { { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_ETGUS2 }, AX178 },
+ { { USB_VENDOR_JVC, USB_PRODUCT_JVC_MP_PRX1}, 0 },
{ { USB_VENDOR_LINKSYS2, USB_PRODUCT_LINKSYS2_USB200M}, 0 },
+ { { USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_USB1000 }, AX178 },
+ { { USB_VENDOR_LOGITEC, USB_PRODUCT_LOGITEC_LAN_GTJU2}, AX178 },
+ { { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAU2GT}, AX178 },
{ { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAU2KTX}, 0 },
+ { { USB_VENDOR_MSI, USB_PRODUCT_MSI_AX88772A}, AX772 },
{ { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_FA120}, 0 },
- { { USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_LN029}, 0 },
+ { { USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01PLUS }, AX772 },
+ { { USB_VENDOR_PLANEX3, USB_PRODUCT_PLANEX3_GU1000T }, AX178 },
{ { USB_VENDOR_SYSTEMTALKS, USB_PRODUCT_SYSTEMTALKS_SGCX2UL}, 0 },
+ { { USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_LN029}, 0 },
+ { { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN028 }, AX178 }
};
#define axe_lookup(v, p) ((const struct axe_type *)usb_lookup(axe_devs, v, p))
@@ -193,6 +239,9 @@ Static void axe_setmulti(struct axe_soft
Static void axe_lock_mii(struct axe_softc *sc);
Static void axe_unlock_mii(struct axe_softc *sc);
+void axe_ax88178_init(struct axe_softc *);
+void axe_ax88772_init(struct axe_softc *);
+
/* Get exclusive access to the MII registers */
Static void
axe_lock_mii(struct axe_softc *sc)
@@ -317,6 +366,23 @@ axe_miibus_statchg(device_t dev)
val = AXE_MEDIA_FULL_DUPLEX;
else
val = 0;
+
+ if (sc->axe_flags & AX178 || sc->axe_flags & AX772) {
+ val |= (AXE_178_MEDIA_RX_EN | AXE_178_MEDIA_MAGIC);
+
+ switch (IFM_SUBTYPE(mii->mii_media_active)) {
+ case IFM_1000_T:
+ val |= AXE_178_MEDIA_GMII | AXE_178_MEDIA_ENCK;
+ break;
+ case IFM_100_TX:
+ val |= AXE_178_MEDIA_100TX;
+ break;
+ case IFM_10_T:
+ /* doesn't need to be handled */
+ break;
+ }
+ }
+
DPRINTF(("axe_miibus_statchg: val=0x%x\n", val));
axe_lock_mii(sc);
err = axe_cmd(sc, AXE_CMD_WRITE_MEDIA, 0, val, NULL);
@@ -347,9 +413,10 @@ axe_setmulti(struct axe_softc *sc)
rxmode = le16toh(rxmode);
if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
- allmulti:
+allmulti:
rxmode |= AXE_RXCMD_ALLMULTI;
axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL);
+ axe_unlock_mii(sc);
return;
} else
rxmode &= ~AXE_RXCMD_ALLMULTI;
@@ -389,6 +456,103 @@ axe_reset(struct axe_softc *sc)
return;
}
+void
+axe_ax88178_init(struct axe_softc *sc)
+{
+ int gpio0 = 0, phymode = 0;
+ u_int16_t eeprom;
+
+ axe_cmd(sc, AXE_CMD_SROM_WR_ENABLE, 0, 0, NULL);
+ /* XXX magic */
+ axe_cmd(sc, AXE_CMD_SROM_READ, 0, 0x0017, &eeprom);
+ axe_cmd(sc, AXE_CMD_SROM_WR_DISABLE, 0, 0, NULL);
+
+ eeprom = letoh16(eeprom);
+
+ DPRINTF((" EEPROM is 0x%x\n", eeprom));
+
+ /* if EEPROM is invalid we have to use to GPIO0 */
+ if (eeprom == 0xffff) {
+ phymode = 0;
+ gpio0 = 1;
+ } else {
+ phymode = eeprom & 7;
+ gpio0 = (eeprom & 0x80) ? 0 : 1;
+ }
+
+ DPRINTF(("use gpio0: %d, phymode %d\n", gpio0, phymode));
+
+ axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x008c, NULL);
+ usbd_delay_ms(sc->axe_udev, 40);
+ if ((eeprom >> 8) != 1) {
+ axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x003c, NULL);
+ usbd_delay_ms(sc->axe_udev, 30);
+
+ axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x001c, NULL);
+ usbd_delay_ms(sc->axe_udev, 300);
+
+ axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x003c, NULL);
+ usbd_delay_ms(sc->axe_udev, 30);
+ } else {
+ DPRINTF(("axe gpio phymode == 1 path\n"));
+ axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x0004, NULL);
+ usbd_delay_ms(sc->axe_udev, 30);
+ axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x000c, NULL);
+ usbd_delay_ms(sc->axe_udev, 30);
+ }
+
+ /* soft reset */
+ axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL);
+ usbd_delay_ms(sc->axe_udev, 150);
+ axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
+ AXE_SW_RESET_PRL | AXE_178_RESET_MAGIC, NULL);
+ usbd_delay_ms(sc->axe_udev, 150);
+ /* Enable MII/GMII/RGMII for external PHY */
+ axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0, NULL);
+ usbd_delay_ms(sc->axe_udev, 10);
+ axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL);
+}
+
+void
+axe_ax88772_init(struct axe_softc *sc)
+{
+ axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x00b0, NULL);
+ usbd_delay_ms(sc->axe_udev, 40);
+
+ if (sc->axe_phyaddrs[1] == AXE_INTPHY) {
+ /* ask for the embedded PHY */
+ axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x01, NULL);
+ usbd_delay_ms(sc->axe_udev, 10);
+
+ /* power down and reset state, pin reset state */
+ axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL);
+ usbd_delay_ms(sc->axe_udev, 60);
+
+ /* power down/reset state, pin operating state */
+ axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
+ AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL);
+ usbd_delay_ms(sc->axe_udev, 150);
+
+ /* power up, reset */
+ axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRL, NULL);
+
+ /* power up, operating */
+ axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
+ AXE_SW_RESET_IPRL | AXE_SW_RESET_PRL, NULL);
+ } else {
+ /* ask for external PHY */
+ axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x00, NULL);
+ usbd_delay_ms(sc->axe_udev, 10);
+
+ /* power down internal PHY */
+ axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
+ AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL);
+ }
+
+ usbd_delay_ms(sc->axe_udev, 150);
+ axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL);
+}
+
/*
* Probe for a AX88172 chip.
*/
@@ -436,6 +600,8 @@ axe_attach(device_t parent, device_t sel
return;
}
+ sc->axe_flags = axe_lookup(uaa->vendor, uaa->product)->axe_flags;
+
usb_init_task(&sc->axe_tick_task, axe_tick_task, sc);
mutex_init(&sc->axe_mii_lock, MUTEX_DEFAULT, IPL_NONE);
usb_init_task(&sc->axe_stop_task, (void (*)(void *))axe_stop, sc);
@@ -452,6 +618,13 @@ axe_attach(device_t parent, device_t sel
id = usbd_get_interface_descriptor(sc->axe_iface);
+ /* decide on what our bufsize will be */
+ if (sc->axe_flags & AX178 || sc->axe_flags & AX772)
+ sc->axe_bufsz = (sc->axe_udev->speed == USB_SPEED_HIGH) ?
+ AXE_178_MAX_BUFSZ : AXE_178_MIN_BUFSZ;
+ else
+ sc->axe_bufsz = AXE_172_BUFSZ;
+
/* Find endpoints. */
for (i = 0; i < id->bNumEndpoints; i++) {
ed = usbd_interface2endpoint_descriptor(sc->axe_iface, i);
@@ -473,11 +646,22 @@ axe_attach(device_t parent, device_t sel
s = splnet();
+ /* We need the PHYID for init dance in some cases */
+ axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, (void *)&sc->axe_phyaddrs);
+
+ if (sc->axe_flags & AX178)
+ axe_ax88178_init(sc);
+ else if (sc->axe_flags & AX772)
+ axe_ax88772_init(sc);
+
/*
* Get station address.
*/
axe_lock_mii(sc);
- axe_cmd(sc, AXE_CMD_READ_NODEID, 0, 0, &eaddr);
+ if (sc->axe_flags & AX178 || sc->axe_flags & AX772)
+ axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, &eaddr);
+ else
+ axe_cmd(sc, AXE_172_CMD_READ_NODEID, 0, 0, &eaddr);
/*
* Load IPG values and PHY indexes.
@@ -495,8 +679,8 @@ axe_attach(device_t parent, device_t sel
/*
* An ASIX chip was detected. Inform the world.
*/
- aprint_normal_dev(self, "Ethernet address %s\n",
- ether_sprintf(eaddr));
+ aprint_normal_dev(self, "Ethernet address %s\n", ether_sprintf(eaddr));
+ memcpy(&sc->init_eaddr, &eaddr, sizeof(sc->init_eaddr));
/* Initialize interface info.*/
ifp = GET_IFP(sc);
@@ -697,7 +881,8 @@ axe_rx_list_init(struct axe_softc *sc)
c->axe_xfer = usbd_alloc_xfer(sc->axe_udev);
if (c->axe_xfer == NULL)
return (ENOBUFS);
- c->axe_buf = usbd_alloc_buffer(c->axe_xfer, AXE_BUFSZ);
+ c->axe_buf = usbd_alloc_buffer(c->axe_xfer,
+ sc->axe_bufsz);
if (c->axe_buf == NULL) {
usbd_free_xfer(c->axe_xfer);
return (ENOBUFS);
@@ -727,7 +912,8 @@ axe_tx_list_init(struct axe_softc *sc)
c->axe_xfer = usbd_alloc_xfer(sc->axe_udev);
if (c->axe_xfer == NULL)
return (ENOBUFS);
- c->axe_buf = usbd_alloc_buffer(c->axe_xfer, AXE_BUFSZ);
+ c->axe_buf = usbd_alloc_buffer(c->axe_xfer,
+ sc->axe_bufsz);
if (c->axe_buf == NULL) {
usbd_free_xfer(c->axe_xfer);
return (ENOBUFS);
@@ -757,7 +943,7 @@ axe_rxstart(struct ifnet *ifp)
/* Setup new transfer. */
usbd_setup_xfer(c->axe_xfer, sc->axe_ep[AXE_ENDPT_RX],
- c, mtod(c->axe_mbuf, char *), AXE_BUFSZ, USBD_SHORT_XFER_OK,
+ c, mtod(c->axe_mbuf, char *), sc->axe_bufsz, USBD_SHORT_XFER_OK,
USBD_NO_TIMEOUT, axe_rxeof);
usbd_transfer(c->axe_xfer);
axe_unlock_mii(sc);
@@ -776,12 +962,16 @@ axe_rxeof(usbd_xfer_handle xfer, usbd_pr
struct axe_softc *sc;
struct axe_chain *c;
struct ifnet *ifp;
- struct mbuf *m;
+ u_char *buf;
u_int32_t total_len;
+ u_int16_t pktlen = 0;
+ struct mbuf *m;
+ struct axe_sframe_hdr hdr;
int s;
- c = priv;
+ c = (struct axe_chain *)priv;
sc = c->axe_sc;
+ buf = c->axe_buf;
ifp = GET_IFP(sc);
DPRINTFN(10,("%s: %s: enter\n", USBDEVNAME(sc->axe_dev),__func__));
@@ -806,44 +996,75 @@ axe_rxeof(usbd_xfer_handle xfer, usbd_pr
usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
- m = c->axe_mbuf;
+ do {
+ if (sc->axe_flags & AX178 || sc->axe_flags & AX772) {
+ if (total_len < sizeof(hdr)) {
+ ifp->if_ierrors++;
+ goto done;
+ }
+ buf += pktlen;
- if (total_len <= sizeof(struct ether_header)) {
- ifp->if_ierrors++;
- goto done;
- }
+ memcpy(&hdr, buf, sizeof(hdr));
+ total_len -= sizeof(hdr);
- ifp->if_ipackets++;
- m->m_pkthdr.rcvif = ifp;
- m->m_pkthdr.len = m->m_len = total_len;
+ if ((hdr.len ^ hdr.ilen) != 0xffff) {
+ ifp->if_ierrors++;
+ goto done;
+ }
+ pktlen = letoh16(hdr.len);
+ if (pktlen > total_len) {
+ ifp->if_ierrors++;
+ goto done;
+ }
+ buf += sizeof(hdr);
- memcpy(mtod(c->axe_mbuf, char *), c->axe_buf, total_len);
+ if ((pktlen % 2) != 0)
+ pktlen++;
- /* No errors; receive the packet. */
- total_len -= ETHER_CRC_LEN + 4;
+ if (total_len < pktlen)
+ total_len = 0;
+ else
+ total_len -= pktlen;
+ } else { /* AX172 */
+ pktlen = total_len;
+ total_len = 0;
+ }
- s = splnet();
+ m = c->axe_mbuf;
- /* XXX ugly */
- if (axe_newbuf(sc, c, NULL) == ENOBUFS) {
- ifp->if_ierrors++;
- goto done1;
- }
+ /* XXX ugly */
+ if (axe_newbuf(sc, c, NULL) == ENOBUFS) {
+ ifp->if_ierrors++;
+ goto done;
+ }
- bpf_mtap(ifp, m);
+ ifp->if_ipackets++;
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = pktlen;
- DPRINTFN(10,("%s: %s: deliver %d\n", USBDEVNAME(sc->axe_dev),
- __func__, m->m_len));
- (*(ifp)->if_input)((ifp), (m));
- done1:
- splx(s);
+ memcpy(mtod(m, char *), buf, pktlen);
+
+ /* No errors; receive the packet. */
+ pktlen -= ETHER_CRC_LEN + 4;
+
+ s = splnet();
+
+ bpf_mtap(ifp, m);
+
+ DPRINTFN(10,("%s: %s: deliver %d\n", USBDEVNAME(sc->axe_dev),
+ __func__, m->m_len));
+ (*(ifp)->if_input)((ifp), (m));
+
+ splx(s);
+
+ } while (total_len > 0);
done:
/* Setup new transfer. */
usbd_setup_xfer(xfer, sc->axe_ep[AXE_ENDPT_RX],
- c, c->axe_buf, AXE_BUFSZ,
+ c, c->axe_buf, sc->axe_bufsz,
USBD_SHORT_XFER_OK | USBD_NO_COPY,
USBD_NO_TIMEOUT, axe_rxeof);
usbd_transfer(xfer);
@@ -958,6 +1179,8 @@ axe_encap(struct axe_softc *sc, struct m
{
struct axe_chain *c;
usbd_status err;
+ struct axe_sframe_hdr hdr;
+ int length, boundary;
c = &sc->axe_cdata.axe_tx_chain[idx];
@@ -965,11 +1188,32 @@ axe_encap(struct axe_softc *sc, struct m
* Copy the mbuf data into a contiguous buffer, leaving two
* bytes at the beginning to hold the frame length.
*/
- m_copydata(m, 0, m->m_pkthdr.len, c->axe_buf);
+ if (sc->axe_flags & AX178 || sc->axe_flags & AX772) {
+ boundary = (sc->axe_udev->speed == USB_SPEED_HIGH) ? 512 : 64;
+
+ hdr.len = htole16(m->m_pkthdr.len);
+ hdr.ilen = ~hdr.len;
+
+ memcpy(c->axe_buf, &hdr, sizeof(hdr));
+ length = sizeof(hdr);
+
+ m_copydata(m, 0, m->m_pkthdr.len, c->axe_buf + length);
+ length += m->m_pkthdr.len;
+
+ if ((length % boundary) == 0) {
+ hdr.len = 0x0000;
+ hdr.ilen = 0xffff;
+ memcpy(c->axe_buf + length, &hdr, sizeof(hdr));
+ length += sizeof(hdr);
+ }
+ } else {
+ m_copydata(m, 0, m->m_pkthdr.len, c->axe_buf);
+ length = m->m_pkthdr.len;
+ }
c->axe_mbuf = m;
usbd_setup_xfer(c->axe_xfer, sc->axe_ep[AXE_ENDPT_TX],
- c, c->axe_buf, m->m_pkthdr.len, USBD_FORCE_SHORT_XFER, 10000,
+ c, c->axe_buf, length, USBD_FORCE_SHORT_XFER, 10000,
axe_txeof);
/* Transmit */
@@ -1042,6 +1286,16 @@ axe_init(void *xsc)
*/
axe_reset(sc);
+ /* Set MAC address */
+ if (sc->axe_flags & AX178 || sc->axe_flags & AX772)
+ axe_cmd(sc, AXE_178_CMD_WRITE_NODEID, 0, 0,
+#if defined(__NetBSD__)
+ &sc->init_eaddr
+#else
+ &sc->arpcom.ac_enaddr
+#endif
+ );
+
/* Enable RX logic. */
/* Init RX ring. */
@@ -1060,12 +1314,24 @@ axe_init(void *xsc)
/* Set transmitter IPG values */
axe_lock_mii(sc);
- axe_cmd(sc, AXE_CMD_WRITE_IPG0, 0, sc->axe_ipgs[0], NULL);
- axe_cmd(sc, AXE_CMD_WRITE_IPG1, 0, sc->axe_ipgs[1], NULL);
- axe_cmd(sc, AXE_CMD_WRITE_IPG2, 0, sc->axe_ipgs[2], NULL);
+ if (sc->axe_flags & AX178 || sc->axe_flags & AX772)
+ axe_cmd(sc, AXE_178_CMD_WRITE_IPG012, sc->axe_ipgs[2],
+ (sc->axe_ipgs[1] << 8) | (sc->axe_ipgs[0]), NULL);
+ else {
+ axe_cmd(sc, AXE_172_CMD_WRITE_IPG0, 0, sc->axe_ipgs[0], NULL);
+ axe_cmd(sc, AXE_172_CMD_WRITE_IPG1, 0, sc->axe_ipgs[1], NULL);
+ axe_cmd(sc, AXE_172_CMD_WRITE_IPG2, 0, sc->axe_ipgs[2], NULL);
+ }
/* Enable receiver, set RX mode */
- rxmode = AXE_RXCMD_UNICAST|AXE_RXCMD_MULTICAST|AXE_RXCMD_ENABLE;
+ rxmode = AXE_RXCMD_MULTICAST|AXE_RXCMD_ENABLE;
+ if (sc->axe_flags & AX178 || sc->axe_flags & AX772) {
+ if (sc->axe_udev->speed == USB_SPEED_HIGH) {
+ /* Largest possible USB buffer size for AX88178 */
+ rxmode |= AXE_178_RXCMD_MFB;
+ }
+ } else
+ rxmode |= AXE_172_RXCMD_UNICAST;
/* If we want promiscuous mode, set the allframes bit. */
if (ifp->if_flags & IFF_PROMISC)
@@ -1103,7 +1369,7 @@ axe_init(void *xsc)
for (i = 0; i < AXE_RX_LIST_CNT; i++) {
c = &sc->axe_cdata.axe_rx_chain[i];
usbd_setup_xfer(c->axe_xfer, sc->axe_ep[AXE_ENDPT_RX],
- c, mtod(c->axe_mbuf, char *), AXE_BUFSZ,
+ c, mtod(c->axe_mbuf, char *), sc->axe_bufsz,
USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, axe_rxeof);
usbd_transfer(c->axe_xfer);
}
Index: if_axereg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_axereg.h,v
retrieving revision 1.7
diff -u -p -r1.7 if_axereg.h
--- if_axereg.h 4 Sep 2009 18:10:08 -0000 1.7
+++ if_axereg.h 13 Jun 2010 08:40:37 -0000
@@ -55,9 +55,11 @@
#define AXE_CMD_LEN(x) (((x) & 0xF000) >> 12)
#define AXE_CMD_CMD(x) ((x) & 0x00FF)
-#define AXE_CMD_READ_RXTX_SRAM 0x2002
-#define AXE_CMD_WRITE_RX_SRAM 0x0103
-#define AXE_CMD_WRITE_TX_SRAM 0x0104
+#define AXE_172_CMD_READ_RXTX_SRAM 0x2002
+#define AXE_182_CMD_READ_RXTX_SRAM 0x6002
+#define AXE_172_CMD_WRITE_RX_SRAM 0x0103
+#define AXE_172_CMD_WRITE_TX_SRAM 0x0104
+#define AXE_182_CMD_WRITE_RXTX_SRAM 0x8103
#define AXE_CMD_MII_OPMODE_SW 0x0106
#define AXE_CMD_MII_READ_REG 0x2007
#define AXE_CMD_MII_WRITE_REG 0x2108
@@ -70,36 +72,74 @@
#define AXE_CMD_RXCTL_READ 0x200F
#define AXE_CMD_RXCTL_WRITE 0x0110
#define AXE_CMD_READ_IPG012 0x3011
-#define AXE_CMD_WRITE_IPG0 0x0112
-#define AXE_CMD_WRITE_IPG1 0x0113
-#define AXE_CMD_WRITE_IPG2 0x0114
+#define AXE_172_CMD_WRITE_IPG0 0x0112
+#define AXE_172_CMD_WRITE_IPG1 0x0113
+#define AXE_172_CMD_WRITE_IPG2 0x0114
+#define AXE_178_CMD_WRITE_IPG012 0x0112
#define AXE_CMD_READ_MCAST 0x8015
#define AXE_CMD_WRITE_MCAST 0x8116
-#define AXE_CMD_READ_NODEID 0x6017
-#define AXE_CMD_WRITE_NODEID 0x6118
+#define AXE_172_CMD_READ_NODEID 0x6017
+#define AXE_172_CMD_WRITE_NODEID 0x6118
+#define AXE_178_CMD_READ_NODEID 0x6013
+#define AXE_178_CMD_WRITE_NODEID 0x6114
#define AXE_CMD_READ_PHYID 0x2019
-#define AXE_CMD_READ_MEDIA 0x101A
+#define AXE_172_CMD_READ_MEDIA 0x101A
+#define AXE_178_CMD_READ_MEDIA 0x201A
#define AXE_CMD_WRITE_MEDIA 0x011B
#define AXE_CMD_READ_MONITOR_MODE 0x101C
#define AXE_CMD_WRITE_MONITOR_MODE 0x011D
#define AXE_CMD_READ_GPIO 0x101E
#define AXE_CMD_WRITE_GPIO 0x011F
-
-#define AXE_MEDIA_FULL_DUPLEX 0x02
-#define AXE_MEDIA_TX_ABORT_ALLOW 0x04
-#define AXE_MEDIA_FLOW_CONTROL_EN 0x10
+#define AXE_CMD_SW_RESET_REG 0x0120
+#define AXE_CMD_SW_PHY_STATUS 0x0021
+#define AXE_CMD_SW_PHY_SELECT 0x0122
+
+#define AXE_SW_RESET_CLEAR 0x00
+#define AXE_SW_RESET_RR 0x01
+#define AXE_SW_RESET_RT 0x02
+#define AXE_SW_RESET_PRTE 0x04
+#define AXE_SW_RESET_PRL 0x08
+#define AXE_SW_RESET_BZ 0x10
+#define AXE_SW_RESET_IPRL 0x20
+#define AXE_SW_RESET_IPPD 0x40
+
+/* AX88178 documentation says to always write this bit... */
+#define AXE_178_RESET_MAGIC 0x40
+
+#define AXE_178_MEDIA_GMII 0x0001
+#define AXE_MEDIA_FULL_DUPLEX 0x0002
+#define AXE_172_MEDIA_TX_ABORT_ALLOW 0x0004
+/* AX88178 documentation says to always write 1 to reserved bit... */
+#define AXE_178_MEDIA_MAGIC 0x0004
+#define AXE_178_MEDIA_ENCK 0x0008
+#define AXE_172_MEDIA_FLOW_CONTROL_EN 0x0010
+#define AXE_178_MEDIA_RXFLOW_CONTROL_EN 0x0010
+#define AXE_178_MEDIA_TXFLOW_CONTROL_EN 0x0020
+#define AXE_178_MEDIA_JUMBO_EN 0x0040
+#define AXE_178_MEDIA_LTPF_ONLY 0x0080
+#define AXE_178_MEDIA_RX_EN 0x0100
+#define AXE_178_MEDIA_100TX 0x0200
+#define AXE_178_MEDIA_SBP 0x0800
+#define AXE_178_MEDIA_SUPERMAC 0x1000
#define AXE_RXCMD_PROMISC 0x0001
#define AXE_RXCMD_ALLMULTI 0x0002
-#define AXE_RXCMD_UNICAST 0x0004
+#define AXE_172_RXCMD_UNICAST 0x0004
+#define AXE_178_RXCMD_KEEP_INVALID_CRC 0x0004
#define AXE_RXCMD_BROADCAST 0x0008
#define AXE_RXCMD_MULTICAST 0x0010
#define AXE_RXCMD_ENABLE 0x0080
+#define AXE_178_RXCMD_MFB 0x0300
#define AXE_NOPHY 0xE0
+#define AXE_INTPHY 0x10
#define AXE_TIMEOUT 1000
-#define AXE_BUFSZ 1536
+
+#define AXE_172_BUFSZ 1536
+#define AXE_178_MIN_BUFSZ 2048
+#define AXE_178_MAX_BUFSZ 16384
+
#define AXE_MIN_FRAMELEN 60
#define AXE_RX_FRAMES 1
#define AXE_TX_FRAMES 1
@@ -125,7 +165,8 @@
struct axe_type {
struct usb_devno axe_dev;
u_int16_t axe_flags;
-/* XXX No flags so far */
+#define AX178 0x0001 /* AX88178 */
+#define AX772 0x0002 /* AX88772 */
};
struct axe_softc;
@@ -148,6 +189,11 @@ struct axe_cdata {
int axe_rx_prod;
};
+struct axe_sframe_hdr {
+ u_int16_t len;
+ u_int16_t ilen;
+} __packed;
+
#define AXE_INC(x, y) (x) = (x + 1) % y
struct axe_softc {
@@ -164,6 +210,7 @@ struct axe_softc {
u_int16_t axe_vendor;
u_int16_t axe_product;
+ u_int16_t axe_flags;
int axe_ed[AXE_ENDPT_MAX];
usbd_pipe_handle axe_ep[AXE_ENDPT_MAX];
@@ -183,6 +230,8 @@ struct axe_softc {
unsigned char axe_ipgs[3];
unsigned char axe_phyaddrs[2];
struct timeval axe_rx_notice;
+ int axe_bufsz;
+ u_char init_eaddr[ETHER_ADDR_LEN];
};
#if 0
Home |
Main Index |
Thread Index |
Old Index