Deleted Added
full compact
34c34
< __FBSDID("$FreeBSD: head/sys/dev/usb/net/if_axe.c 226479 2011-10-17 19:51:38Z yongari $");
---
> __FBSDID("$FreeBSD: head/sys/dev/usb/net/if_axe.c 226743 2011-10-25 18:36:18Z yongari $");
79,80d78
< #include <sys/stdint.h>
< #include <sys/stddef.h>
82,83d79
< #include <sys/queue.h>
< #include <sys/types.h>
85d80
< #include <sys/kernel.h>
87c82,84
< #include <sys/module.h>
---
> #include <sys/condvar.h>
> #include <sys/endian.h>
> #include <sys/kernel.h>
88a86,88
> #include <sys/malloc.h>
> #include <sys/mbuf.h>
> #include <sys/module.h>
90c90,91
< #include <sys/condvar.h>
---
> #include <sys/socket.h>
> #include <sys/sockio.h>
93,96d93
< #include <sys/unistd.h>
< #include <sys/callout.h>
< #include <sys/malloc.h>
< #include <sys/priv.h>
97a95,103
> #include <net/if.h>
> #include <net/ethernet.h>
> #include <net/if_types.h>
> #include <net/if_media.h>
> #include <net/if_vlan_var.h>
>
> #include <dev/mii/mii.h>
> #include <dev/mii/miivar.h>
>
124a131,132
> #define AXE_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP)
>
188a197
> static int axe_attach_post_sub(struct usb_ether *);
197a207,211
> static int axe_ioctl(struct ifnet *, u_long, caddr_t);
> static int axe_rx_frame(struct usb_ether *, struct usb_page_cache *, int);
> static int axe_rxeof(struct usb_ether *, struct usb_page_cache *,
> unsigned int offset, unsigned int, struct axe_csum_hdr *);
> static void axe_csum_cfg(struct usb_ether *);
268a283
> .ue_attach_post_sub = axe_attach_post_sub,
307,309d321
< if (sc->sc_phyno != phy)
< return (0);
<
341,344d352
<
< if (sc->sc_phyno != phy)
< return (0);
<
375c383
<
---
>
393c401
<
---
>
397c405
<
---
>
399c407
< if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0)
---
> if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) {
400a409,417
> if (AXE_IS_178_FAMILY(sc)) {
> if ((IFM_OPTIONS(mii->mii_media_active) &
> IFM_ETH_TXPAUSE) != 0)
> val |= AXE_178_MEDIA_TXFLOW_CONTROL_EN;
> if ((IFM_OPTIONS(mii->mii_media_active) &
> IFM_ETH_RXPAUSE) != 0)
> val |= AXE_178_MEDIA_RXFLOW_CONTROL_EN;
> }
> }
847a865,911
> static int
> axe_attach_post_sub(struct usb_ether *ue)
> {
> struct axe_softc *sc;
> struct ifnet *ifp;
> u_int adv_pause;
> int error;
>
> sc = uether_getsc(ue);
> ifp = ue->ue_ifp;
> ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
> ifp->if_start = uether_start;
> ifp->if_ioctl = axe_ioctl;
> ifp->if_init = uether_init;
> IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
> ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
> IFQ_SET_READY(&ifp->if_snd);
>
> if (AXE_IS_178_FAMILY(sc))
> ifp->if_capabilities |= IFCAP_VLAN_MTU;
> if (sc->sc_flags & AXE_FLAG_772B) {
> ifp->if_capabilities |= IFCAP_TXCSUM | IFCAP_RXCSUM;
> ifp->if_hwassist = AXE_CSUM_FEATURES;
> /*
> * Checksum offloading of AX88772B also works with VLAN
> * tagged frames but there is no way to take advantage
> * of the feature because vlan(4) assumes
> * IFCAP_VLAN_HWTAGGING is prerequisite condition to
> * support checksum offloading with VLAN. VLAN hardware
> * tagging support of AX88772B is very limited so it's
> * not possible to announce IFCAP_VLAN_HWTAGGING.
> */
> }
> ifp->if_capenable = ifp->if_capabilities;
> if (sc->sc_flags & (AXE_FLAG_772A | AXE_FLAG_772B | AXE_FLAG_178))
> adv_pause = MIIF_DOPAUSE;
> else
> adv_pause = 0;
> mtx_lock(&Giant);
> error = mii_attach(ue->ue_dev, &ue->ue_miibus, ifp,
> uether_ifmedia_upd, ue->ue_methods->ue_mii_sts,
> BMSR_DEFCAPMASK, sc->sc_phyno, MII_OFFSET_ANY, adv_pause);
> mtx_unlock(&Giant);
>
> return (error);
> }
>
933,934d996
< struct ifnet *ifp = uether_getifp(ue);
< struct axe_sframe_hdr hdr;
936d997
< int err, pos, len;
943,946d1003
< pos = 0;
< len = 0;
< err = 0;
<
948,955c1005
< if (AXE_IS_178_FAMILY(sc)) {
< while (pos < actlen) {
< if ((pos + sizeof(hdr)) > actlen) {
< /* too little data */
< err = EINVAL;
< break;
< }
< usbd_copy_out(pc, pos, &hdr, sizeof(hdr));
---
> axe_rx_frame(ue, pc, actlen);
957,979d1006
< if ((hdr.len ^ hdr.ilen) != 0xFFFF) {
< /* we lost sync */
< err = EINVAL;
< break;
< }
< pos += sizeof(hdr);
<
< len = le16toh(hdr.len);
< if ((pos + len) > actlen) {
< /* invalid length */
< err = EINVAL;
< break;
< }
< uether_rxbuf(ue, pc, pos, len);
<
< pos += len + (len % 2);
< }
< } else
< uether_rxbuf(ue, pc, 0, actlen);
<
< if (err != 0)
< ifp->if_ierrors++;
<
1000a1028,1152
> static int
> axe_rx_frame(struct usb_ether *ue, struct usb_page_cache *pc, int actlen)
> {
> struct axe_softc *sc;
> struct axe_sframe_hdr hdr;
> struct axe_csum_hdr csum_hdr;
> int error, len, pos;
>
> sc = uether_getsc(ue);
> pos = 0;
> len = 0;
> error = 0;
> if ((sc->sc_flags & AXE_FLAG_STD_FRAME) != 0) {
> while (pos < actlen) {
> if ((pos + sizeof(hdr)) > actlen) {
> /* too little data */
> error = EINVAL;
> break;
> }
> usbd_copy_out(pc, pos, &hdr, sizeof(hdr));
>
> if ((hdr.len ^ hdr.ilen) != sc->sc_lenmask) {
> /* we lost sync */
> error = EINVAL;
> break;
> }
> pos += sizeof(hdr);
> len = le16toh(hdr.len);
> if (pos + len > actlen) {
> /* invalid length */
> error = EINVAL;
> break;
> }
> axe_rxeof(ue, pc, pos, len, NULL);
> pos += len + (len % 2);
> }
> } else if ((sc->sc_flags & AXE_FLAG_CSUM_FRAME) != 0) {
> while (pos < actlen) {
> if ((pos + sizeof(csum_hdr)) > actlen) {
> /* too little data */
> error = EINVAL;
> break;
> }
> usbd_copy_out(pc, pos, &csum_hdr, sizeof(csum_hdr));
>
> csum_hdr.len = le16toh(csum_hdr.len);
> csum_hdr.ilen = le16toh(csum_hdr.ilen);
> csum_hdr.cstatus = le16toh(csum_hdr.cstatus);
> if ((AXE_CSUM_RXBYTES(csum_hdr.len) ^
> AXE_CSUM_RXBYTES(csum_hdr.ilen)) !=
> sc->sc_lenmask) {
> /* we lost sync */
> error = EINVAL;
> break;
> }
> /*
> * Get total transferred frame length including
> * checksum header. The length should be multiple
> * of 4.
> */
> len = sizeof(csum_hdr) + AXE_CSUM_RXBYTES(csum_hdr.len);
> len = (len + 3) & ~3;
> if (pos + len > actlen) {
> /* invalid length */
> error = EINVAL;
> break;
> }
> axe_rxeof(ue, pc, pos + sizeof(csum_hdr),
> AXE_CSUM_RXBYTES(csum_hdr.len), &csum_hdr);
> pos += len;
> }
> } else
> axe_rxeof(ue, pc, 0, actlen, NULL);
>
> if (error != 0)
> ue->ue_ifp->if_ierrors++;
> return (error);
> }
>
> static int
> axe_rxeof(struct usb_ether *ue, struct usb_page_cache *pc, unsigned int offset,
> unsigned int len, struct axe_csum_hdr *csum_hdr)
> {
> struct ifnet *ifp = ue->ue_ifp;
> struct mbuf *m;
>
> if (len < ETHER_HDR_LEN || len > MCLBYTES - ETHER_ALIGN) {
> ifp->if_ierrors++;
> return (EINVAL);
> }
>
> m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
> if (m == NULL) {
> ifp->if_iqdrops++;
> return (ENOMEM);
> }
> m->m_len = m->m_pkthdr.len = MCLBYTES;
> m_adj(m, ETHER_ALIGN);
>
> usbd_copy_out(pc, offset, mtod(m, uint8_t *), len);
>
> ifp->if_ipackets++;
> m->m_pkthdr.rcvif = ifp;
> m->m_pkthdr.len = m->m_len = len;
>
> if (csum_hdr != NULL && csum_hdr->cstatus & AXE_CSUM_HDR_L3_TYPE_IPV4) {
> if ((csum_hdr->cstatus & (AXE_CSUM_HDR_L4_CSUM_ERR |
> AXE_CSUM_HDR_L3_CSUM_ERR)) == 0) {
> m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED |
> CSUM_IP_VALID;
> if ((csum_hdr->cstatus & AXE_CSUM_HDR_L4_TYPE_MASK) ==
> AXE_CSUM_HDR_L4_TYPE_TCP ||
> (csum_hdr->cstatus & AXE_CSUM_HDR_L4_TYPE_MASK) ==
> AXE_CSUM_HDR_L4_TYPE_UDP) {
> m->m_pkthdr.csum_flags |=
> CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
> m->m_pkthdr.csum_data = 0xffff;
> }
> }
> }
>
> _IF_ENQUEUE(&ue->ue_rxq, m);
> return (0);
> }
>
1042a1195,1209
> /*
> * If upper stack computed checksum, driver
> * should tell controller not to insert
> * computed checksum for checksum offloading
> * enabled controller.
> */
> if (ifp->if_capabilities & IFCAP_TXCSUM) {
> if ((m->m_pkthdr.csum_flags &
> AXE_CSUM_FEATURES) != 0)
> hdr.len |= htole16(
> AXE_TX_CSUM_PSEUDO_HDR);
> else
> hdr.len |= htole16(
> AXE_TX_CSUM_DIS);
> }
1133a1301,1328
> axe_csum_cfg(struct usb_ether *ue)
> {
> struct axe_softc *sc;
> struct ifnet *ifp;
> uint16_t csum1, csum2;
>
> sc = uether_getsc(ue);
> AXE_LOCK_ASSERT(sc, MA_OWNED);
>
> if ((sc->sc_flags & AXE_FLAG_772B) != 0) {
> ifp = uether_getifp(ue);
> csum1 = 0;
> csum2 = 0;
> if ((ifp->if_capenable & IFCAP_TXCSUM) != 0)
> csum1 |= AXE_TXCSUM_IP | AXE_TXCSUM_TCP |
> AXE_TXCSUM_UDP;
> axe_cmd(sc, AXE_772B_CMD_WRITE_TXCSUM, csum2, csum1, NULL);
> csum1 = 0;
> csum2 = 0;
> if ((ifp->if_capenable & IFCAP_RXCSUM) != 0)
> csum1 |= AXE_RXCSUM_IP | AXE_RXCSUM_IPVE |
> AXE_RXCSUM_TCP | AXE_RXCSUM_UDP | AXE_RXCSUM_ICMP |
> AXE_RXCSUM_IGMP;
> axe_cmd(sc, AXE_772B_CMD_WRITE_RXCSUM, csum2, csum1, NULL);
> }
> }
>
> static void
1150,1151c1345,1346
< /* Set MAC address. */
< if (AXE_IS_178_FAMILY(sc))
---
> /* Set MAC address and transmitter IPG values. */
> if (AXE_IS_178_FAMILY(sc)) {
1153,1157d1347
< else
< axe_cmd(sc, AXE_172_CMD_WRITE_NODEID, 0, 0, IF_LLADDR(ifp));
<
< /* Set transmitter IPG values */
< if (AXE_IS_178_FAMILY(sc))
1160c1350,1351
< else {
---
> } else {
> axe_cmd(sc, AXE_172_CMD_WRITE_NODEID, 0, 0, IF_LLADDR(ifp));
1166,1167c1357,1374
< /* AX88772B uses different maximum frame burst configuration. */
< if (sc->sc_flags & AXE_FLAG_772B)
---
> if (AXE_IS_178_FAMILY(sc)) {
> sc->sc_flags &= ~(AXE_FLAG_STD_FRAME | AXE_FLAG_CSUM_FRAME);
> if ((sc->sc_flags & AXE_FLAG_772B) != 0)
> sc->sc_lenmask = AXE_CSUM_HDR_LEN_MASK;
> else
> sc->sc_lenmask = AXE_HDR_LEN_MASK;
> if ((sc->sc_flags & AXE_FLAG_772B) != 0 &&
> (ifp->if_capenable & IFCAP_RXCSUM) != 0)
> sc->sc_flags |= AXE_FLAG_CSUM_FRAME;
> else
> sc->sc_flags |= AXE_FLAG_STD_FRAME;
> }
>
> /* Configure TX/RX checksum offloading. */
> axe_csum_cfg(ue);
>
> if (sc->sc_flags & AXE_FLAG_772B) {
> /* AX88772B uses different maximum frame burst configuration. */
1170a1378
> }
1178c1386,1387
< * header on 4 byte boundary is not needed
---
> * header on 4 byte boundary is not needed when
> * checksum offloading feature is not used
1180c1389,1392
< * RX handler.
---
> * RX handler. When RX checksum offloading is
> * active, aligning IP header is required to
> * reflect actual frame length including RX
> * header size.
1182a1395,1396
> if ((ifp->if_capenable & IFCAP_RXCSUM) != 0)
> rxmode |= AXE_772B_RXCMD_IPHDR_ALIGN;
1211d1424
< axe_start(ue);
1252a1466,1507
>
> static int
> axe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
> {
> struct usb_ether *ue = ifp->if_softc;
> struct axe_softc *sc;
> struct ifreq *ifr;
> int error, mask, reinit;
>
> sc = uether_getsc(ue);
> ifr = (struct ifreq *)data;
> error = 0;
> reinit = 0;
> if (cmd == SIOCSIFCAP) {
> AXE_LOCK(sc);
> mask = ifr->ifr_reqcap ^ ifp->if_capenable;
> if ((mask & IFCAP_TXCSUM) != 0 &&
> (ifp->if_capabilities & IFCAP_TXCSUM) != 0) {
> ifp->if_capenable ^= IFCAP_TXCSUM;
> if ((ifp->if_capenable & IFCAP_TXCSUM) != 0)
> ifp->if_hwassist |= AXE_CSUM_FEATURES;
> else
> ifp->if_hwassist &= ~AXE_CSUM_FEATURES;
> reinit++;
> }
> if ((mask & IFCAP_RXCSUM) != 0 &&
> (ifp->if_capabilities & IFCAP_RXCSUM) != 0) {
> ifp->if_capenable ^= IFCAP_RXCSUM;
> reinit++;
> }
> if (reinit > 0 && ifp->if_drv_flags & IFF_DRV_RUNNING)
> ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
> else
> reinit = 0;
> AXE_UNLOCK(sc);
> if (reinit > 0)
> uether_init(ue);
> } else
> error = uether_ioctl(ifp, cmd, data);
>
> return (error);
> }