aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorSam Leffler <sam@FreeBSD.org>2007-11-10 16:23:38 +0000
committerSam Leffler <sam@FreeBSD.org>2007-11-10 16:23:38 +0000
commitb0db4c9328c1bc870c5cf76d527ef9e5d602dfd1 (patch)
tree50cf651e33beccae42321d4927c8bf664a7e35fa /sys
parent433ea89af4f7413891e69b8c0a94503a82a2bac7 (diff)
Notes
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/usb/if_axe.c287
-rw-r--r--sys/dev/usb/if_axereg.h45
2 files changed, 223 insertions, 109 deletions
diff --git a/sys/dev/usb/if_axe.c b/sys/dev/usb/if_axe.c
index 84dd0e0226976..db65d10019b42 100644
--- a/sys/dev/usb/if_axe.c
+++ b/sys/dev/usb/if_axe.c
@@ -104,6 +104,21 @@ __FBSDID("$FreeBSD$");
/* "device miibus" required. See GENERIC if you get errors here. */
#include "miibus_if.h"
+/*
+ * AXE_178_MAX_FRAME_BURST
+ * max frame burst size for Ax88178 and Ax88772
+ * 0 2048 bytes
+ * 1 4096 bytes
+ * 2 8192 bytes
+ * 3 16384 bytes
+ * use the largest your system can handle without usb stalling.
+ *
+ * NB: 88772 parts appear to generate lots of input errors with
+ * a 2K rx buffer and 8K is only slightly faster than 4K on an
+ * EHCI port on a T42 so change at your own risk.
+ */
+#define AXE_178_MAX_FRAME_BURST 1
+
#include <dev/usb/if_axereg.h>
/*
@@ -151,7 +166,6 @@ static void axe_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
static void axe_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
static void axe_tick(void *);
static void axe_tick_task(void *);
-static void axe_rxstart(struct ifnet *);
static void axe_start(struct ifnet *);
static int axe_ioctl(struct ifnet *, u_long, caddr_t);
static void axe_init(void *);
@@ -548,7 +562,6 @@ axe_attach(device_t self)
}
sc->axe_boundary = 64;
-#if 0
if (sc->axe_flags & (AX178|AX772)) {
if (sc->axe_udev->speed == USB_SPEED_HIGH) {
sc->axe_bufsz = AXE_178_MAX_BUFSZ;
@@ -556,10 +569,7 @@ axe_attach(device_t self)
} else
sc->axe_bufsz = AXE_178_MIN_BUFSZ;
} else
- sc->axe_bufsz = AXE_172_BUFSZ
-#else
- sc->axe_bufsz = AXE_172_BUFSZ;
-#endif
+ sc->axe_bufsz = AXE_172_BUFSZ;
{ /* XXX debug */
device_printf(sc->axe_dev, "%s, bufsz %d, boundary %d\n",
sc->axe_flags & AX178 ? "AX88178" :
@@ -643,9 +653,6 @@ device_printf(sc->axe_dev, "%s, bufsz %d, boundary %d\n",
ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
IFQ_SET_READY(&ifp->if_snd);
- sc->axe_qdat.ifp = ifp;
- sc->axe_qdat.if_rxstart = axe_rxstart;
-
if (mii_phy_probe(self, &sc->axe_miibus,
axe_ifmedia_upd, axe_ifmedia_sts)) {
device_printf(sc->axe_dev, "MII without any PHY!\n");
@@ -704,33 +711,97 @@ axe_detach(device_t dev)
return(0);
}
+static int
+axe_rx_list_init(struct axe_softc *sc)
+{
+ struct axe_cdata *cd;
+ struct axe_chain *c;
+ int i;
+
+ cd = &sc->axe_cdata;
+ for (i = 0; i < AXE_RX_LIST_CNT; i++) {
+ c = &cd->axe_rx_chain[i];
+ c->axe_sc = sc;
+ c->axe_idx = i;
+ c->axe_mbuf = NULL;
+ if (c->axe_xfer == NULL) {
+ 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,
+ sc->axe_bufsz);
+ if (c->axe_buf == NULL) {
+ usbd_free_xfer(c->axe_xfer);
+ return (ENOBUFS);
+ }
+ }
+ }
+
+ return (0);
+}
+
static void
-axe_rxstart(struct ifnet *ifp)
+axe_rx_list_free(struct axe_softc *sc)
{
- struct axe_softc *sc;
- struct ue_chain *c;
+ int i;
- sc = ifp->if_softc;
- AXE_LOCK(sc);
- c = &sc->axe_cdata.ue_rx_chain[sc->axe_cdata.ue_rx_prod];
+ for (i = 0; i < AXE_RX_LIST_CNT; i++) {
+ if (sc->axe_cdata.axe_rx_chain[i].axe_mbuf != NULL) {
+ m_freem(sc->axe_cdata.axe_rx_chain[i].axe_mbuf);
+ sc->axe_cdata.axe_rx_chain[i].axe_mbuf = NULL;
+ }
+ if (sc->axe_cdata.axe_rx_chain[i].axe_xfer != NULL) {
+ usbd_free_xfer(sc->axe_cdata.axe_rx_chain[i].axe_xfer);
+ sc->axe_cdata.axe_rx_chain[i].axe_xfer = NULL;
+ }
+ }
+}
- c->ue_mbuf = usb_ether_newbuf();
- if (c->ue_mbuf == NULL) {
- device_printf(sc->axe_dev, "no memory for rx list "
- "-- packet dropped!\n");
- ifp->if_ierrors++;
- AXE_UNLOCK(sc);
- return;
+static int
+axe_tx_list_init(struct axe_softc *sc)
+{
+ struct axe_cdata *cd;
+ struct axe_chain *c;
+ int i;
+
+ cd = &sc->axe_cdata;
+ for (i = 0; i < AXE_TX_LIST_CNT; i++) {
+ c = &cd->axe_tx_chain[i];
+ c->axe_sc = sc;
+ c->axe_idx = i;
+ c->axe_mbuf = NULL;
+ if (c->axe_xfer == NULL) {
+ 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,
+ sc->axe_bufsz);
+ if (c->axe_buf == NULL) {
+ usbd_free_xfer(c->axe_xfer);
+ return (ENOBUFS);
+ }
+ }
}
- /* Setup new transfer. */
- usbd_setup_xfer(c->ue_xfer, sc->axe_ep[AXE_ENDPT_RX],
- c, mtod(c->ue_mbuf, char *), UE_BUFSZ, USBD_SHORT_XFER_OK,
- USBD_NO_TIMEOUT, axe_rxeof);
- usbd_transfer(c->ue_xfer);
- AXE_UNLOCK(sc);
+ return (0);
+}
- return;
+static void
+axe_tx_list_free(struct axe_softc *sc)
+{
+ int i;
+
+ /* Free TX resources. */
+ for (i = 0; i < AXE_TX_LIST_CNT; i++) {
+ if (sc->axe_cdata.axe_tx_chain[i].axe_mbuf != NULL) {
+ m_freem(sc->axe_cdata.axe_tx_chain[i].axe_mbuf);
+ sc->axe_cdata.axe_tx_chain[i].axe_mbuf = NULL;
+ }
+ if (sc->axe_cdata.axe_tx_chain[i].axe_xfer != NULL) {
+ usbd_free_xfer(sc->axe_cdata.axe_tx_chain[i].axe_xfer);
+ sc->axe_cdata.axe_tx_chain[i].axe_xfer = NULL;
+ }
+ }
}
/*
@@ -741,14 +812,15 @@ static void
axe_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
{
struct axe_softc *sc;
- struct ue_chain *c;
+ struct axe_chain *c = (struct axe_chain *) priv;
struct mbuf *m;
+ u_char *buf;
struct ifnet *ifp;
- struct axe_sframe_hdr hdr;
- int total_len = 0, pktlen;
+ struct axe_sframe_hdr *hdr;
+ int total_len = 0;
+ int pktlen = 0;
- c = priv;
- sc = c->ue_sc;
+ sc = c->axe_sc;
AXE_LOCK(sc);
ifp = sc->axe_ifp;
@@ -772,49 +844,61 @@ axe_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
- m = c->ue_mbuf;
- /* XXX don't handle multiple packets in one transfer */
- if (sc->axe_flags & (AX178|AX772)) {
- if (total_len < sizeof(hdr)) {
- ifp->if_ierrors++;
- goto done;
- }
- m_copydata(m, 0, sizeof(hdr), (caddr_t) &hdr);
- total_len -= sizeof(hdr);
+ buf = c->axe_buf;
- if ((hdr.len ^ hdr.ilen) != 0xffff) {
- ifp->if_ierrors++;
- goto done;
+ do {
+ if (sc->axe_flags & (AX178|AX772)) {
+ if (total_len < sizeof(struct axe_sframe_hdr)) {
+ ifp->if_ierrors++;
+ goto done;
+ }
+ if ((pktlen % 2) != 0)
+ pktlen++;
+ buf += pktlen;
+
+ hdr = (struct axe_sframe_hdr *) buf;
+ total_len -= sizeof(struct axe_sframe_hdr);
+ if ((hdr->len ^ hdr->ilen) != 0xffff) {
+ ifp->if_ierrors++;
+ goto done;
+ }
+ pktlen = le16toh(hdr->len);
+ if (pktlen > total_len) {
+ ifp->if_ierrors++;
+ goto done;
+ }
+
+ buf += sizeof(struct axe_sframe_hdr);
+ total_len -= pktlen + (pktlen % 2);
+ } else {
+ pktlen = total_len;
+ total_len = 0;
}
- pktlen = le16toh(hdr.len);
- if (pktlen > total_len) {
+
+ if (pktlen < sizeof(struct ether_header)) {
ifp->if_ierrors++;
goto done;
}
- m_adj(m, sizeof(hdr));
- } else {
- if (total_len < sizeof(struct ether_header)) {
+ m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (m == NULL) {
ifp->if_ierrors++;
goto done;
}
- pktlen = total_len;
- }
-
- ifp->if_ipackets++;
- m->m_pkthdr.rcvif = (void *)&sc->axe_qdat;
- m->m_pkthdr.len = m->m_len = pktlen;
-
- /* Put the packet on the special USB input queue. */
- usb_ether_input(m);
- AXE_UNLOCK(sc);
+ m->m_data += ETHER_ALIGN;
+ memcpy(mtod(m, void *), buf, pktlen);
+ m->m_pkthdr.len = m->m_len = pktlen;
+ m->m_pkthdr.rcvif = ifp;
- return;
+ ifp->if_input(ifp, m);
+ ifp->if_ipackets++;
+ } while (total_len > 0);
+ /* fall thru... */
done:
/* Setup new transfer. */
- usbd_setup_xfer(c->ue_xfer, sc->axe_ep[AXE_ENDPT_RX],
- c, mtod(c->ue_mbuf, char *), UE_BUFSZ, USBD_SHORT_XFER_OK,
+ usbd_setup_xfer(xfer, sc->axe_ep[AXE_ENDPT_RX],
+ c, c->axe_buf, sc->axe_bufsz, USBD_SHORT_XFER_OK | USBD_NO_COPY,
USBD_NO_TIMEOUT, axe_rxeof);
- usbd_transfer(c->ue_xfer);
+ usbd_transfer(xfer);
AXE_UNLOCK(sc);
return;
@@ -829,12 +913,12 @@ static void
axe_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
{
struct axe_softc *sc;
- struct ue_chain *c;
+ struct axe_chain *c;
struct ifnet *ifp;
usbd_status err;
c = priv;
- sc = c->ue_sc;
+ sc = c->axe_sc;
AXE_LOCK(sc);
ifp = sc->axe_ifp;
@@ -853,12 +937,11 @@ axe_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
ifp->if_timer = 0;
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
- usbd_get_xfer_status(c->ue_xfer, NULL, NULL, NULL, &err);
+ usbd_get_xfer_status(c->axe_xfer, NULL, NULL, NULL, &err);
- if (c->ue_mbuf != NULL) {
- c->ue_mbuf->m_pkthdr.rcvif = ifp;
- usb_tx_done(c->ue_mbuf);
- c->ue_mbuf = NULL;
+ if (c->axe_mbuf != NULL) {
+ m_freem(c->axe_mbuf);
+ c->axe_mbuf = NULL;
}
if (err)
@@ -868,6 +951,9 @@ axe_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
AXE_UNLOCK(sc);
+ if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+ axe_start(ifp);
+
return;
}
@@ -927,12 +1013,12 @@ axe_tick_task(void *xsc)
static int
axe_encap(struct axe_softc *sc, struct mbuf *m, int idx)
{
- struct ue_chain *c;
+ struct axe_chain *c;
usbd_status err;
struct axe_sframe_hdr hdr;
int length;
- c = &sc->axe_cdata.ue_tx_chain[idx];
+ c = &sc->axe_cdata.axe_tx_chain[idx];
/*
* Copy the mbuf data into a contiguous buffer, leaving two
@@ -942,29 +1028,29 @@ axe_encap(struct axe_softc *sc, struct mbuf *m, int idx)
hdr.len = htole16(m->m_pkthdr.len);
hdr.ilen = ~hdr.len;
- memcpy(c->ue_buf, &hdr, sizeof(hdr));
+ memcpy(c->axe_buf, &hdr, sizeof(hdr));
length = sizeof(hdr);
- m_copydata(m, 0, m->m_pkthdr.len, c->ue_buf + sizeof(hdr));
+ m_copydata(m, 0, m->m_pkthdr.len, c->axe_buf + length);
length += m->m_pkthdr.len;
if ((length % sc->axe_boundary) == 0) {
hdr.len = 0;
hdr.ilen = 0xffff;
- memcpy(c->ue_buf + length, &hdr, sizeof(hdr));
+ memcpy(c->axe_buf + length, &hdr, sizeof(hdr));
length += sizeof(hdr);
}
} else {
- m_copydata(m, 0, m->m_pkthdr.len, c->ue_buf);
+ m_copydata(m, 0, m->m_pkthdr.len, c->axe_buf);
length = m->m_pkthdr.len;
}
- c->ue_mbuf = m;
+ c->axe_mbuf = m;
- usbd_setup_xfer(c->ue_xfer, sc->axe_ep[AXE_ENDPT_TX],
- c, c->ue_buf, length, USBD_FORCE_SHORT_XFER, 10000, axe_txeof);
+ usbd_setup_xfer(c->axe_xfer, sc->axe_ep[AXE_ENDPT_TX],
+ c, c->axe_buf, length, USBD_FORCE_SHORT_XFER, 10000, axe_txeof);
/* Transmit */
- err = usbd_transfer(c->ue_xfer);
+ err = usbd_transfer(c->axe_xfer);
if (err != USBD_IN_PROGRESS) {
/* XXX probably don't want to sleep here */
AXE_SLEEPLOCK(sc);
@@ -973,7 +1059,7 @@ axe_encap(struct axe_softc *sc, struct mbuf *m, int idx)
return(EIO);
}
- sc->axe_cdata.ue_tx_cnt++;
+ sc->axe_cdata.axe_tx_cnt++;
return(0);
}
@@ -1032,7 +1118,7 @@ axe_init(void *xsc)
{
struct axe_softc *sc = xsc;
struct ifnet *ifp = sc->axe_ifp;
- struct ue_chain *c;
+ struct axe_chain *c;
usbd_status err;
int i;
int rxmode;
@@ -1057,8 +1143,7 @@ axe_init(void *xsc)
/* Enable RX logic. */
/* Init TX ring. */
- if (usb_ether_tx_list_init(sc, &sc->axe_cdata,
- sc->axe_udev) == ENOBUFS) {
+ if (axe_tx_list_init(sc) == ENOBUFS) {
device_printf(sc->axe_dev, "tx list init failed\n");
AXE_UNLOCK(sc);
AXE_SLEEPUNLOCK(sc);
@@ -1066,8 +1151,7 @@ axe_init(void *xsc)
}
/* Init RX ring. */
- if (usb_ether_rx_list_init(sc, &sc->axe_cdata,
- sc->axe_udev) == ENOBUFS) {
+ if (axe_rx_list_init(sc) == ENOBUFS) {
device_printf(sc->axe_dev, "rx list init failed\n");
AXE_UNLOCK(sc);
AXE_SLEEPUNLOCK(sc);
@@ -1088,7 +1172,7 @@ axe_init(void *xsc)
rxmode = AXE_RXCMD_MULTICAST|AXE_RXCMD_ENABLE;
if (sc->axe_flags & (AX178|AX772)) {
if (sc->axe_bufsz == AXE_178_MAX_BUFSZ)
- rxmode |= AXE_178_RXCMD_MFB_16384;
+ rxmode |= AXE_178_RXCMD_MFB;
} else
rxmode |= AXE_172_RXCMD_UNICAST;
@@ -1126,12 +1210,13 @@ axe_init(void *xsc)
}
/* Start up the receive pipe. */
- for (i = 0; i < UE_RX_LIST_CNT; i++) {
- c = &sc->axe_cdata.ue_rx_chain[i];
- usbd_setup_xfer(c->ue_xfer, sc->axe_ep[AXE_ENDPT_RX],
- c, mtod(c->ue_mbuf, char *), UE_BUFSZ,
- USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, axe_rxeof);
- usbd_transfer(c->ue_xfer);
+ 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, c->axe_buf, sc->axe_bufsz,
+ USBD_SHORT_XFER_OK | USBD_NO_COPY,
+ USBD_NO_TIMEOUT, axe_rxeof);
+ usbd_transfer(c->axe_xfer);
}
ifp->if_drv_flags |= IFF_DRV_RUNNING;
@@ -1222,7 +1307,7 @@ static void
axe_watchdog(struct ifnet *ifp)
{
struct axe_softc *sc;
- struct ue_chain *c;
+ struct axe_chain *c;
usbd_status stat;
sc = ifp->if_softc;
@@ -1231,9 +1316,9 @@ axe_watchdog(struct ifnet *ifp)
ifp->if_oerrors++;
device_printf(sc->axe_dev, "watchdog timeout\n");
- c = &sc->axe_cdata.ue_tx_chain[0];
- usbd_get_xfer_status(c->ue_xfer, NULL, NULL, NULL, &stat);
- axe_txeof(c->ue_xfer, c, stat);
+ c = &sc->axe_cdata.axe_tx_chain[0];
+ usbd_get_xfer_status(c->axe_xfer, NULL, NULL, NULL, &stat);
+ axe_txeof(c->axe_xfer, c, stat);
AXE_UNLOCK(sc);
@@ -1307,9 +1392,9 @@ axe_stop(struct axe_softc *sc)
axe_reset(sc);
/* Free RX resources. */
- usb_ether_rx_list_free(&sc->axe_cdata);
+ axe_rx_list_free(sc);
/* Free TX resources. */
- usb_ether_tx_list_free(&sc->axe_cdata);
+ axe_tx_list_free(sc);
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
sc->axe_link = 0;
diff --git a/sys/dev/usb/if_axereg.h b/sys/dev/usb/if_axereg.h
index 15bbaf5891c28..4503b198bbe1a 100644
--- a/sys/dev/usb/if_axereg.h
+++ b/sys/dev/usb/if_axereg.h
@@ -129,11 +129,10 @@
#define AXE_RXCMD_MULTICAST 0x0010
#define AXE_178_RXCMD_AP 0x0020
#define AXE_RXCMD_ENABLE 0x0080
-#define AXE_178_RXCMD_MFB 0x0300 /* Max Frame Burst */
-#define AXE_178_RXCMD_MFB_2048 0x0000
-#define AXE_178_RXCMD_MFB_4096 0x0100
-#define AXE_178_RXCMD_MFB_8192 0x0200
-#define AXE_178_RXCMD_MFB_16384 0x0300
+#define AXE_178_RXCMD_MFB_2048 0x0000 /* 2K max frame burst */
+#define AXE_178_RXCMD_MFB_4096 0x0100 /* 4K max frame burst */
+#define AXE_178_RXCMD_MFB_8192 0x0200 /* 8K max frame burst */
+#define AXE_178_RXCMD_MFB_16384 0x0300 /* 16K max frame burst*/
#define AXE_NOPHY 0xE0
#define AXE_INTPHY 0x10
@@ -141,14 +140,45 @@
#define AXE_TIMEOUT 1000
#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
+#if AXE_178_MAX_FRAME_BURST == 0
+#define AXE_178_RXCMD_MFB AXE_178_RXCMD_MFB_2048
+#define AXE_178_MAX_BUFSZ 2048
+#elif AXE_178_MAX_FRAME_BURST == 1
+#define AXE_178_RXCMD_MFB AXE_178_RXCMD_MFB_4096
+#define AXE_178_MAX_BUFSZ 4096
+#elif AXE_178_MAX_FRAME_BURST == 2
+#define AXE_178_RXCMD_MFB AXE_178_RXCMD_MFB_8192
+#define AXE_178_MAX_BUFSZ 8192
+#else
+#define AXE_178_RXCMD_MFB AXE_178_RXCMD_MFB_16384
+#define AXE_178_MAX_BUFSZ 16384
+#endif
+
#define AXE_RX_LIST_CNT 1
#define AXE_TX_LIST_CNT 1
+struct axe_chain {
+ struct axe_softc *axe_sc;
+ usbd_xfer_handle axe_xfer;
+ char *axe_buf;
+ struct mbuf *axe_mbuf;
+ int axe_accum;
+ int axe_idx;
+};
+
+struct axe_cdata {
+ struct axe_chain axe_tx_chain[AXE_TX_LIST_CNT];
+ struct axe_chain axe_rx_chain[AXE_RX_LIST_CNT];
+ int axe_tx_prod;
+ int axe_tx_cons;
+ int axe_tx_cnt;
+ int axe_rx_prod;
+};
+
#define AXE_CTL_READ 0x01
#define AXE_CTL_WRITE 0x02
@@ -198,7 +228,7 @@ struct axe_softc {
int axe_ed[AXE_ENDPT_MAX];
usbd_pipe_handle axe_ep[AXE_ENDPT_MAX];
int axe_if_flags;
- struct ue_cdata axe_cdata;
+ struct axe_cdata axe_cdata;
struct callout_handle axe_stat_ch;
struct mtx axe_mtx;
struct sx axe_sleeplock;
@@ -207,7 +237,6 @@ struct axe_softc {
unsigned char axe_ipgs[3];
unsigned char axe_phyaddrs[2];
struct timeval axe_rx_notice;
- struct usb_qdat axe_qdat;
struct usb_task axe_tick_task;
int axe_bufsz;
int axe_boundary;