| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: if_wm.c,v 1.233 2012/08/30 23:14:20 msaitoh Exp $ */ | | 1 | /* $NetBSD: if_wm.c,v 1.234 2012/09/01 02:08:28 matt Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc. | | 4 | * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Written by Jason R. Thorpe for Wasabi Systems, Inc. | | 7 | * Written by Jason R. Thorpe for Wasabi Systems, Inc. |
8 | * | | 8 | * |
9 | * Redistribution and use in source and binary forms, with or without | | 9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | | 10 | * modification, are permitted provided that the following conditions |
11 | * are met: | | 11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright | | 12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. | | 13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright | | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
| @@ -66,27 +66,27 @@ | | | @@ -66,27 +66,27 @@ |
66 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 66 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
67 | POSSIBILITY OF SUCH DAMAGE. | | 67 | POSSIBILITY OF SUCH DAMAGE. |
68 | | | 68 | |
69 | *******************************************************************************/ | | 69 | *******************************************************************************/ |
70 | /* | | 70 | /* |
71 | * Device driver for the Intel i8254x family of Gigabit Ethernet chips. | | 71 | * Device driver for the Intel i8254x family of Gigabit Ethernet chips. |
72 | * | | 72 | * |
73 | * TODO (in order of importance): | | 73 | * TODO (in order of importance): |
74 | * | | 74 | * |
75 | * - Rework how parameters are loaded from the EEPROM. | | 75 | * - Rework how parameters are loaded from the EEPROM. |
76 | */ | | 76 | */ |
77 | | | 77 | |
78 | #include <sys/cdefs.h> | | 78 | #include <sys/cdefs.h> |
79 | __KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.233 2012/08/30 23:14:20 msaitoh Exp $"); | | 79 | __KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.234 2012/09/01 02:08:28 matt Exp $"); |
80 | | | 80 | |
81 | #include <sys/param.h> | | 81 | #include <sys/param.h> |
82 | #include <sys/systm.h> | | 82 | #include <sys/systm.h> |
83 | #include <sys/callout.h> | | 83 | #include <sys/callout.h> |
84 | #include <sys/mbuf.h> | | 84 | #include <sys/mbuf.h> |
85 | #include <sys/malloc.h> | | 85 | #include <sys/malloc.h> |
86 | #include <sys/kernel.h> | | 86 | #include <sys/kernel.h> |
87 | #include <sys/socket.h> | | 87 | #include <sys/socket.h> |
88 | #include <sys/ioctl.h> | | 88 | #include <sys/ioctl.h> |
89 | #include <sys/errno.h> | | 89 | #include <sys/errno.h> |
90 | #include <sys/device.h> | | 90 | #include <sys/device.h> |
91 | #include <sys/queue.h> | | 91 | #include <sys/queue.h> |
92 | #include <sys/syslog.h> | | 92 | #include <sys/syslog.h> |
| @@ -2776,26 +2776,28 @@ static int | | | @@ -2776,26 +2776,28 @@ static int |
2776 | wm_nq_tx_offload(struct wm_softc *sc, struct wm_txsoft *txs, | | 2776 | wm_nq_tx_offload(struct wm_softc *sc, struct wm_txsoft *txs, |
2777 | uint32_t *cmdlenp, uint32_t *fieldsp, bool *do_csum) | | 2777 | uint32_t *cmdlenp, uint32_t *fieldsp, bool *do_csum) |
2778 | { | | 2778 | { |
2779 | struct mbuf *m0 = txs->txs_mbuf; | | 2779 | struct mbuf *m0 = txs->txs_mbuf; |
2780 | struct m_tag *mtag; | | 2780 | struct m_tag *mtag; |
2781 | uint32_t vl_len, mssidx, cmdc; | | 2781 | uint32_t vl_len, mssidx, cmdc; |
2782 | struct ether_header *eh; | | 2782 | struct ether_header *eh; |
2783 | int offset, iphl; | | 2783 | int offset, iphl; |
2784 | | | 2784 | |
2785 | /* | | 2785 | /* |
2786 | * XXX It would be nice if the mbuf pkthdr had offset | | 2786 | * XXX It would be nice if the mbuf pkthdr had offset |
2787 | * fields for the protocol headers. | | 2787 | * fields for the protocol headers. |
2788 | */ | | 2788 | */ |
| | | 2789 | *cmdlenp = 0; |
| | | 2790 | *fieldsp = 0; |
2789 | | | 2791 | |
2790 | eh = mtod(m0, struct ether_header *); | | 2792 | eh = mtod(m0, struct ether_header *); |
2791 | switch (htons(eh->ether_type)) { | | 2793 | switch (htons(eh->ether_type)) { |
2792 | case ETHERTYPE_IP: | | 2794 | case ETHERTYPE_IP: |
2793 | case ETHERTYPE_IPV6: | | 2795 | case ETHERTYPE_IPV6: |
2794 | offset = ETHER_HDR_LEN; | | 2796 | offset = ETHER_HDR_LEN; |
2795 | break; | | 2797 | break; |
2796 | | | 2798 | |
2797 | case ETHERTYPE_VLAN: | | 2799 | case ETHERTYPE_VLAN: |
2798 | offset = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | | 2800 | offset = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; |
2799 | break; | | 2801 | break; |
2800 | | | 2802 | |
2801 | default: | | 2803 | default: |
| @@ -2817,27 +2819,26 @@ wm_nq_tx_offload(struct wm_softc *sc, st | | | @@ -2817,27 +2819,26 @@ wm_nq_tx_offload(struct wm_softc *sc, st |
2817 | iphl = M_CSUM_DATA_IPv4_IPHL(m0->m_pkthdr.csum_data); | | 2819 | iphl = M_CSUM_DATA_IPv4_IPHL(m0->m_pkthdr.csum_data); |
2818 | } else { | | 2820 | } else { |
2819 | iphl = M_CSUM_DATA_IPv6_HL(m0->m_pkthdr.csum_data); | | 2821 | iphl = M_CSUM_DATA_IPv6_HL(m0->m_pkthdr.csum_data); |
2820 | } | | 2822 | } |
2821 | vl_len |= (iphl << NQTXC_VLLEN_IPLEN_SHIFT); | | 2823 | vl_len |= (iphl << NQTXC_VLLEN_IPLEN_SHIFT); |
2822 | KASSERT((iphl & ~NQTXC_VLLEN_IPLEN_MASK) == 0); | | 2824 | KASSERT((iphl & ~NQTXC_VLLEN_IPLEN_MASK) == 0); |
2823 | | | 2825 | |
2824 | if ((mtag = VLAN_OUTPUT_TAG(&sc->sc_ethercom, m0)) != NULL) { | | 2826 | if ((mtag = VLAN_OUTPUT_TAG(&sc->sc_ethercom, m0)) != NULL) { |
2825 | vl_len |= ((VLAN_TAG_VALUE(mtag) & NQTXC_VLLEN_VLAN_MASK) | | 2827 | vl_len |= ((VLAN_TAG_VALUE(mtag) & NQTXC_VLLEN_VLAN_MASK) |
2826 | << NQTXC_VLLEN_VLAN_SHIFT); | | 2828 | << NQTXC_VLLEN_VLAN_SHIFT); |
2827 | *cmdlenp |= NQTX_CMD_VLE; | | 2829 | *cmdlenp |= NQTX_CMD_VLE; |
2828 | } | | 2830 | } |
2829 | | | 2831 | |
2830 | *fieldsp = 0; | | | |
2831 | mssidx = 0; | | 2832 | mssidx = 0; |
2832 | | | 2833 | |
2833 | if ((m0->m_pkthdr.csum_flags & (M_CSUM_TSOv4 | M_CSUM_TSOv6)) != 0) { | | 2834 | if ((m0->m_pkthdr.csum_flags & (M_CSUM_TSOv4 | M_CSUM_TSOv6)) != 0) { |
2834 | int hlen = offset + iphl; | | 2835 | int hlen = offset + iphl; |
2835 | int tcp_hlen; | | 2836 | int tcp_hlen; |
2836 | bool v4 = (m0->m_pkthdr.csum_flags & M_CSUM_TSOv4) != 0; | | 2837 | bool v4 = (m0->m_pkthdr.csum_flags & M_CSUM_TSOv4) != 0; |
2837 | | | 2838 | |
2838 | if (__predict_false(m0->m_len < | | 2839 | if (__predict_false(m0->m_len < |
2839 | (hlen + sizeof(struct tcphdr)))) { | | 2840 | (hlen + sizeof(struct tcphdr)))) { |
2840 | /* | | 2841 | /* |
2841 | * TCP/IP headers are not in the first mbuf; we need | | 2842 | * TCP/IP headers are not in the first mbuf; we need |
2842 | * to do this the slow and painful way. Let's just | | 2843 | * to do this the slow and painful way. Let's just |
2843 | * hope this doesn't happen very often. | | 2844 | * hope this doesn't happen very often. |
| @@ -2970,27 +2971,26 @@ wm_nq_tx_offload(struct wm_softc *sc, st | | | @@ -2970,27 +2971,26 @@ wm_nq_tx_offload(struct wm_softc *sc, st |
2970 | * | | 2971 | * |
2971 | * Start packet transmission on the interface for NEWQUEUE devices | | 2972 | * Start packet transmission on the interface for NEWQUEUE devices |
2972 | */ | | 2973 | */ |
2973 | static void | | 2974 | static void |
2974 | wm_nq_start(struct ifnet *ifp) | | 2975 | wm_nq_start(struct ifnet *ifp) |
2975 | { | | 2976 | { |
2976 | struct wm_softc *sc = ifp->if_softc; | | 2977 | struct wm_softc *sc = ifp->if_softc; |
2977 | struct mbuf *m0; | | 2978 | struct mbuf *m0; |
2978 | struct m_tag *mtag; | | 2979 | struct m_tag *mtag; |
2979 | struct wm_txsoft *txs; | | 2980 | struct wm_txsoft *txs; |
2980 | bus_dmamap_t dmamap; | | 2981 | bus_dmamap_t dmamap; |
2981 | int error, nexttx, lasttx = -1, seg, segs_needed; | | 2982 | int error, nexttx, lasttx = -1, seg, segs_needed; |
2982 | bool do_csum, sent; | | 2983 | bool do_csum, sent; |
2983 | uint32_t cmdlen, fields, dcmdlen; | | | |
2984 | | | 2984 | |
2985 | if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING) | | 2985 | if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING) |
2986 | return; | | 2986 | return; |
2987 | | | 2987 | |
2988 | sent = false; | | 2988 | sent = false; |
2989 | | | 2989 | |
2990 | /* | | 2990 | /* |
2991 | * Loop through the send queue, setting up transmit descriptors | | 2991 | * Loop through the send queue, setting up transmit descriptors |
2992 | * until we drain the queue, or use up all available transmit | | 2992 | * until we drain the queue, or use up all available transmit |
2993 | * descriptors. | | 2993 | * descriptors. |
2994 | */ | | 2994 | */ |
2995 | for (;;) { | | 2995 | for (;;) { |
2996 | /* Grab a packet off the queue. */ | | 2996 | /* Grab a packet off the queue. */ |
| @@ -3090,38 +3090,41 @@ wm_nq_start(struct ifnet *ifp) | | | @@ -3090,38 +3090,41 @@ wm_nq_start(struct ifnet *ifp) |
3090 | * Store a pointer to the packet so that we can free it | | 3090 | * Store a pointer to the packet so that we can free it |
3091 | * later. | | 3091 | * later. |
3092 | * | | 3092 | * |
3093 | * Initially, we consider the number of descriptors the | | 3093 | * Initially, we consider the number of descriptors the |
3094 | * packet uses the number of DMA segments. This may be | | 3094 | * packet uses the number of DMA segments. This may be |
3095 | * incremented by 1 if we do checksum offload (a descriptor | | 3095 | * incremented by 1 if we do checksum offload (a descriptor |
3096 | * is used to set the checksum context). | | 3096 | * is used to set the checksum context). |
3097 | */ | | 3097 | */ |
3098 | txs->txs_mbuf = m0; | | 3098 | txs->txs_mbuf = m0; |
3099 | txs->txs_firstdesc = sc->sc_txnext; | | 3099 | txs->txs_firstdesc = sc->sc_txnext; |
3100 | txs->txs_ndesc = segs_needed; | | 3100 | txs->txs_ndesc = segs_needed; |
3101 | | | 3101 | |
3102 | /* Set up offload parameters for this packet. */ | | 3102 | /* Set up offload parameters for this packet. */ |
| | | 3103 | uint32_t cmdlen, fields, dcmdlen; |
3103 | if (m0->m_pkthdr.csum_flags & | | 3104 | if (m0->m_pkthdr.csum_flags & |
3104 | (M_CSUM_TSOv4|M_CSUM_TSOv6| | | 3105 | (M_CSUM_TSOv4|M_CSUM_TSOv6| |
3105 | M_CSUM_IPv4|M_CSUM_TCPv4|M_CSUM_UDPv4| | | 3106 | M_CSUM_IPv4|M_CSUM_TCPv4|M_CSUM_UDPv4| |
3106 | M_CSUM_TCPv6|M_CSUM_UDPv6)) { | | 3107 | M_CSUM_TCPv6|M_CSUM_UDPv6)) { |
3107 | if (wm_nq_tx_offload(sc, txs, &cmdlen, &fields, | | 3108 | if (wm_nq_tx_offload(sc, txs, &cmdlen, &fields, |
3108 | &do_csum) != 0) { | | 3109 | &do_csum) != 0) { |
3109 | /* Error message already displayed. */ | | 3110 | /* Error message already displayed. */ |
3110 | bus_dmamap_unload(sc->sc_dmat, dmamap); | | 3111 | bus_dmamap_unload(sc->sc_dmat, dmamap); |
3111 | continue; | | 3112 | continue; |
3112 | } | | 3113 | } |
3113 | } else { | | 3114 | } else { |
3114 | do_csum = false; | | 3115 | do_csum = false; |
| | | 3116 | cmdlen = 0; |
| | | 3117 | fields = 0; |
3115 | } | | 3118 | } |
3116 | | | 3119 | |
3117 | /* Sync the DMA map. */ | | 3120 | /* Sync the DMA map. */ |
3118 | bus_dmamap_sync(sc->sc_dmat, dmamap, 0, dmamap->dm_mapsize, | | 3121 | bus_dmamap_sync(sc->sc_dmat, dmamap, 0, dmamap->dm_mapsize, |
3119 | BUS_DMASYNC_PREWRITE); | | 3122 | BUS_DMASYNC_PREWRITE); |
3120 | | | 3123 | |
3121 | /* | | 3124 | /* |
3122 | * Initialize the first transmit descriptor. | | 3125 | * Initialize the first transmit descriptor. |
3123 | */ | | 3126 | */ |
3124 | nexttx = sc->sc_txnext; | | 3127 | nexttx = sc->sc_txnext; |
3125 | if (!do_csum) { | | 3128 | if (!do_csum) { |
3126 | /* setup a legacy descriptor */ | | 3129 | /* setup a legacy descriptor */ |
3127 | wm_set_dma_addr( | | 3130 | wm_set_dma_addr( |