| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: if_mec.c,v 1.33 2008/08/23 18:44:51 tsutsui Exp $ */ | | 1 | /* $NetBSD: if_mec.c,v 1.34 2009/03/16 09:58:51 tsutsui Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2004, 2008 Izumi Tsutsui. All rights reserved. | | 4 | * Copyright (c) 2004, 2008 Izumi Tsutsui. All rights reserved. |
5 | * | | 5 | * |
6 | * Redistribution and use in source and binary forms, with or without | | 6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions | | 7 | * modification, are permitted provided that the following conditions |
8 | * are met: | | 8 | * are met: |
9 | * 1. Redistributions of source code must retain the above copyright | | 9 | * 1. Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. | | 10 | * notice, this list of conditions and the following disclaimer. |
11 | * 2. Redistributions in binary form must reproduce the above copyright | | 11 | * 2. Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the | | 12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. | | 13 | * documentation and/or other materials provided with the distribution. |
14 | * | | 14 | * |
| @@ -51,52 +51,58 @@ | | | @@ -51,52 +51,58 @@ |
51 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | | 51 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
52 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | | 52 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
53 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | | 53 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
54 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | | 54 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
55 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | | 55 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
56 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | | 56 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
57 | */ | | 57 | */ |
58 | | | 58 | |
59 | /* | | 59 | /* |
60 | * MACE MAC-110 Ethernet driver | | 60 | * MACE MAC-110 Ethernet driver |
61 | */ | | 61 | */ |
62 | | | 62 | |
63 | #include <sys/cdefs.h> | | 63 | #include <sys/cdefs.h> |
64 | __KERNEL_RCSID(0, "$NetBSD: if_mec.c,v 1.33 2008/08/23 18:44:51 tsutsui Exp $"); | | 64 | __KERNEL_RCSID(0, "$NetBSD: if_mec.c,v 1.34 2009/03/16 09:58:51 tsutsui Exp $"); |
65 | | | 65 | |
66 | #include "opt_ddb.h" | | 66 | #include "opt_ddb.h" |
67 | #include "bpfilter.h" | | 67 | #include "bpfilter.h" |
68 | #include "rnd.h" | | 68 | #include "rnd.h" |
69 | | | 69 | |
70 | #include <sys/param.h> | | 70 | #include <sys/param.h> |
71 | #include <sys/systm.h> | | 71 | #include <sys/systm.h> |
72 | #include <sys/device.h> | | 72 | #include <sys/device.h> |
73 | #include <sys/callout.h> | | 73 | #include <sys/callout.h> |
74 | #include <sys/mbuf.h> | | 74 | #include <sys/mbuf.h> |
75 | #include <sys/malloc.h> | | 75 | #include <sys/malloc.h> |
76 | #include <sys/kernel.h> | | 76 | #include <sys/kernel.h> |
77 | #include <sys/socket.h> | | 77 | #include <sys/socket.h> |
78 | #include <sys/ioctl.h> | | 78 | #include <sys/ioctl.h> |
79 | #include <sys/errno.h> | | 79 | #include <sys/errno.h> |
80 | | | 80 | |
81 | #if NRND > 0 | | 81 | #if NRND > 0 |
82 | #include <sys/rnd.h> | | 82 | #include <sys/rnd.h> |
83 | #endif | | 83 | #endif |
84 | | | 84 | |
85 | #include <net/if.h> | | 85 | #include <net/if.h> |
86 | #include <net/if_dl.h> | | 86 | #include <net/if_dl.h> |
87 | #include <net/if_media.h> | | 87 | #include <net/if_media.h> |
88 | #include <net/if_ether.h> | | 88 | #include <net/if_ether.h> |
89 | | | 89 | |
| | | 90 | #include <netinet/in.h> |
| | | 91 | #include <netinet/in_systm.h> |
| | | 92 | #include <netinet/ip.h> |
| | | 93 | #include <netinet/tcp.h> |
| | | 94 | #include <netinet/udp.h> |
| | | 95 | |
90 | #if NBPFILTER > 0 | | 96 | #if NBPFILTER > 0 |
91 | #include <net/bpf.h> | | 97 | #include <net/bpf.h> |
92 | #endif | | 98 | #endif |
93 | | | 99 | |
94 | #include <machine/bus.h> | | 100 | #include <machine/bus.h> |
95 | #include <machine/intr.h> | | 101 | #include <machine/intr.h> |
96 | #include <machine/machtype.h> | | 102 | #include <machine/machtype.h> |
97 | | | 103 | |
98 | #include <dev/mii/mii.h> | | 104 | #include <dev/mii/mii.h> |
99 | #include <dev/mii/miivar.h> | | 105 | #include <dev/mii/miivar.h> |
100 | | | 106 | |
101 | #include <sgimips/mace/macevar.h> | | 107 | #include <sgimips/mace/macevar.h> |
102 | #include <sgimips/mace/if_mecreg.h> | | 108 | #include <sgimips/mace/if_mecreg.h> |
| @@ -229,26 +235,27 @@ struct mec_rxdesc { | | | @@ -229,26 +235,27 @@ struct mec_rxdesc { |
229 | #define MEC_RXSTAT_VIOLATION 0x0000000000010000 /* code violation (?) */ | | 235 | #define MEC_RXSTAT_VIOLATION 0x0000000000010000 /* code violation (?) */ |
230 | #define MEC_RXSTAT_UNUSED2 0x0000000000020000 /* unknown (?) */ | | 236 | #define MEC_RXSTAT_UNUSED2 0x0000000000020000 /* unknown (?) */ |
231 | #define MEC_RXSTAT_CRCERROR 0x0000000000040000 /* CRC error */ | | 237 | #define MEC_RXSTAT_CRCERROR 0x0000000000040000 /* CRC error */ |
232 | #define MEC_RXSTAT_MULTICAST 0x0000000000080000 /* multicast packet */ | | 238 | #define MEC_RXSTAT_MULTICAST 0x0000000000080000 /* multicast packet */ |
233 | #define MEC_RXSTAT_BROADCAST 0x0000000000100000 /* broadcast packet */ | | 239 | #define MEC_RXSTAT_BROADCAST 0x0000000000100000 /* broadcast packet */ |
234 | #define MEC_RXSTAT_INVALID 0x0000000000200000 /* invalid preamble */ | | 240 | #define MEC_RXSTAT_INVALID 0x0000000000200000 /* invalid preamble */ |
235 | #define MEC_RXSTAT_LONGEVENT 0x0000000000400000 /* long packet */ | | 241 | #define MEC_RXSTAT_LONGEVENT 0x0000000000400000 /* long packet */ |
236 | #define MEC_RXSTAT_BADPACKET 0x0000000000800000 /* bad packet */ | | 242 | #define MEC_RXSTAT_BADPACKET 0x0000000000800000 /* bad packet */ |
237 | #define MEC_RXSTAT_CAREVENT 0x0000000001000000 /* carrier event */ | | 243 | #define MEC_RXSTAT_CAREVENT 0x0000000001000000 /* carrier event */ |
238 | #define MEC_RXSTAT_MATCHMCAST 0x0000000002000000 /* match multicast */ | | 244 | #define MEC_RXSTAT_MATCHMCAST 0x0000000002000000 /* match multicast */ |
239 | #define MEC_RXSTAT_MATCHMAC 0x0000000004000000 /* match MAC */ | | 245 | #define MEC_RXSTAT_MATCHMAC 0x0000000004000000 /* match MAC */ |
240 | #define MEC_RXSTAT_SEQNUM 0x00000000f8000000 /* sequence number */ | | 246 | #define MEC_RXSTAT_SEQNUM 0x00000000f8000000 /* sequence number */ |
241 | #define MEC_RXSTAT_CKSUM 0x0000ffff00000000ULL /* IP checksum */ | | 247 | #define MEC_RXSTAT_CKSUM 0x0000ffff00000000ULL /* IP checksum */ |
| | | 248 | #define RXSTAT_CKSUM(x) (((uint64_t)(x) & MEC_RXSTAT_CKSUM) >> 32) |
242 | #define MEC_RXSTAT_UNUSED1 0x7fff000000000000ULL /* should be zero */ | | 249 | #define MEC_RXSTAT_UNUSED1 0x7fff000000000000ULL /* should be zero */ |
243 | #define MEC_RXSTAT_RECEIVED 0x8000000000000000ULL /* set to 1 on RX */ | | 250 | #define MEC_RXSTAT_RECEIVED 0x8000000000000000ULL /* set to 1 on RX */ |
244 | uint64_t rxd_pad1[MEC_RXD_NRXPAD]; | | 251 | uint64_t rxd_pad1[MEC_RXD_NRXPAD]; |
245 | uint8_t rxd_buf[MEC_RXD_BUFSIZE]; | | 252 | uint8_t rxd_buf[MEC_RXD_BUFSIZE]; |
246 | }; | | 253 | }; |
247 | | | 254 | |
248 | /* | | 255 | /* |
249 | * control structures for DMA ops | | 256 | * control structures for DMA ops |
250 | */ | | 257 | */ |
251 | struct mec_control_data { | | 258 | struct mec_control_data { |
252 | /* | | 259 | /* |
253 | * TX descriptors and buffers | | 260 | * TX descriptors and buffers |
254 | */ | | 261 | */ |
| @@ -396,26 +403,28 @@ static void mec_statchg(device_t); | | | @@ -396,26 +403,28 @@ static void mec_statchg(device_t); |
396 | | | 403 | |
397 | static void enaddr_aton(const char *, uint8_t *); | | 404 | static void enaddr_aton(const char *, uint8_t *); |
398 | | | 405 | |
399 | static int mec_init(struct ifnet * ifp); | | 406 | static int mec_init(struct ifnet * ifp); |
400 | static void mec_start(struct ifnet *); | | 407 | static void mec_start(struct ifnet *); |
401 | static void mec_watchdog(struct ifnet *); | | 408 | static void mec_watchdog(struct ifnet *); |
402 | static void mec_tick(void *); | | 409 | static void mec_tick(void *); |
403 | static int mec_ioctl(struct ifnet *, u_long, void *); | | 410 | static int mec_ioctl(struct ifnet *, u_long, void *); |
404 | static void mec_reset(struct mec_softc *); | | 411 | static void mec_reset(struct mec_softc *); |
405 | static void mec_setfilter(struct mec_softc *); | | 412 | static void mec_setfilter(struct mec_softc *); |
406 | static int mec_intr(void *arg); | | 413 | static int mec_intr(void *arg); |
407 | static void mec_stop(struct ifnet *, int); | | 414 | static void mec_stop(struct ifnet *, int); |
408 | static void mec_rxintr(struct mec_softc *); | | 415 | static void mec_rxintr(struct mec_softc *); |
| | | 416 | static void mec_rxcsum(struct mec_softc *, struct mbuf *, uint16_t, |
| | | 417 | uint32_t); |
409 | static void mec_txintr(struct mec_softc *, uint32_t); | | 418 | static void mec_txintr(struct mec_softc *, uint32_t); |
410 | static void mec_shutdown(void *); | | 419 | static void mec_shutdown(void *); |
411 | | | 420 | |
412 | CFATTACH_DECL_NEW(mec, sizeof(struct mec_softc), | | 421 | CFATTACH_DECL_NEW(mec, sizeof(struct mec_softc), |
413 | mec_match, mec_attach, NULL, NULL); | | 422 | mec_match, mec_attach, NULL, NULL); |
414 | | | 423 | |
415 | static int mec_matched = 0; | | 424 | static int mec_matched = 0; |
416 | | | 425 | |
417 | static int | | 426 | static int |
418 | mec_match(device_t parent, cfdata_t cf, void *aux) | | 427 | mec_match(device_t parent, cfdata_t cf, void *aux) |
419 | { | | 428 | { |
420 | | | 429 | |
421 | /* allow only one device */ | | 430 | /* allow only one device */ |
| @@ -598,26 +607,29 @@ mec_attach(device_t parent, device_t sel | | | @@ -598,26 +607,29 @@ mec_attach(device_t parent, device_t sel |
598 | } | | 607 | } |
599 | | | 608 | |
600 | strcpy(ifp->if_xname, device_xname(self)); | | 609 | strcpy(ifp->if_xname, device_xname(self)); |
601 | ifp->if_softc = sc; | | 610 | ifp->if_softc = sc; |
602 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | | 611 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; |
603 | ifp->if_ioctl = mec_ioctl; | | 612 | ifp->if_ioctl = mec_ioctl; |
604 | ifp->if_start = mec_start; | | 613 | ifp->if_start = mec_start; |
605 | ifp->if_watchdog = mec_watchdog; | | 614 | ifp->if_watchdog = mec_watchdog; |
606 | ifp->if_init = mec_init; | | 615 | ifp->if_init = mec_init; |
607 | ifp->if_stop = mec_stop; | | 616 | ifp->if_stop = mec_stop; |
608 | ifp->if_mtu = ETHERMTU; | | 617 | ifp->if_mtu = ETHERMTU; |
609 | IFQ_SET_READY(&ifp->if_snd); | | 618 | IFQ_SET_READY(&ifp->if_snd); |
610 | | | 619 | |
| | | 620 | /* mec has dumb RX cksum support */ |
| | | 621 | ifp->if_capabilities = IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx; |
| | | 622 | |
611 | /* We can support 802.1Q VLAN-sized frames. */ | | 623 | /* We can support 802.1Q VLAN-sized frames. */ |
612 | sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU; | | 624 | sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU; |
613 | | | 625 | |
614 | /* attach the interface */ | | 626 | /* attach the interface */ |
615 | if_attach(ifp); | | 627 | if_attach(ifp); |
616 | ether_ifattach(ifp, sc->sc_enaddr); | | 628 | ether_ifattach(ifp, sc->sc_enaddr); |
617 | | | 629 | |
618 | /* establish interrupt */ | | 630 | /* establish interrupt */ |
619 | cpu_intr_establish(maa->maa_intr, maa->maa_intrmask, mec_intr, sc); | | 631 | cpu_intr_establish(maa->maa_intr, maa->maa_intrmask, mec_intr, sc); |
620 | | | 632 | |
621 | #if NRND > 0 | | 633 | #if NRND > 0 |
622 | rnd_attach_source(&sc->sc_rnd_source, device_xname(self), | | 634 | rnd_attach_source(&sc->sc_rnd_source, device_xname(self), |
623 | RND_TYPE_NET, 0); | | 635 | RND_TYPE_NET, 0); |
| @@ -1646,26 +1658,27 @@ mec_intr(void *arg) | | | @@ -1646,26 +1658,27 @@ mec_intr(void *arg) |
1646 | } | | 1658 | } |
1647 | | | 1659 | |
1648 | static void | | 1660 | static void |
1649 | mec_rxintr(struct mec_softc *sc) | | 1661 | mec_rxintr(struct mec_softc *sc) |
1650 | { | | 1662 | { |
1651 | bus_space_tag_t st = sc->sc_st; | | 1663 | bus_space_tag_t st = sc->sc_st; |
1652 | bus_space_handle_t sh = sc->sc_sh; | | 1664 | bus_space_handle_t sh = sc->sc_sh; |
1653 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | | 1665 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
1654 | struct mbuf *m; | | 1666 | struct mbuf *m; |
1655 | struct mec_rxdesc *rxd; | | 1667 | struct mec_rxdesc *rxd; |
1656 | uint64_t rxstat; | | 1668 | uint64_t rxstat; |
1657 | u_int len; | | 1669 | u_int len; |
1658 | int i; | | 1670 | int i; |
| | | 1671 | uint32_t crc; |
1659 | | | 1672 | |
1660 | DPRINTF(MEC_DEBUG_RXINTR, ("mec_rxintr: called\n")); | | 1673 | DPRINTF(MEC_DEBUG_RXINTR, ("mec_rxintr: called\n")); |
1661 | | | 1674 | |
1662 | for (i = sc->sc_rxptr;; i = MEC_NEXTRX(i)) { | | 1675 | for (i = sc->sc_rxptr;; i = MEC_NEXTRX(i)) { |
1663 | rxd = &sc->sc_rxdesc[i]; | | 1676 | rxd = &sc->sc_rxdesc[i]; |
1664 | | | 1677 | |
1665 | MEC_RXSTATSYNC(sc, i, BUS_DMASYNC_POSTREAD); | | 1678 | MEC_RXSTATSYNC(sc, i, BUS_DMASYNC_POSTREAD); |
1666 | rxstat = rxd->rxd_stat; | | 1679 | rxstat = rxd->rxd_stat; |
1667 | | | 1680 | |
1668 | DPRINTF(MEC_DEBUG_RXINTR, | | 1681 | DPRINTF(MEC_DEBUG_RXINTR, |
1669 | ("mec_rxintr: rxstat = 0x%016llx, rxptr = %d\n", | | 1682 | ("mec_rxintr: rxstat = 0x%016llx, rxptr = %d\n", |
1670 | rxstat, i)); | | 1683 | rxstat, i)); |
1671 | DPRINTF(MEC_DEBUG_RXINTR, ("mec_rxintr: rxfifo = 0x%08x\n", | | 1684 | DPRINTF(MEC_DEBUG_RXINTR, ("mec_rxintr: rxfifo = 0x%08x\n", |
| @@ -1730,59 +1743,157 @@ mec_rxintr(struct mec_softc *sc) | | | @@ -1730,59 +1743,157 @@ mec_rxintr(struct mec_softc *sc) |
1730 | if ((m->m_flags & M_EXT) == 0) { | | 1743 | if ((m->m_flags & M_EXT) == 0) { |
1731 | printf("%s: unable to allocate RX cluster\n", | | 1744 | printf("%s: unable to allocate RX cluster\n", |
1732 | device_xname(sc->sc_dev)); | | 1745 | device_xname(sc->sc_dev)); |
1733 | m_freem(m); | | 1746 | m_freem(m); |
1734 | m = NULL; | | 1747 | m = NULL; |
1735 | goto dropit; | | 1748 | goto dropit; |
1736 | } | | 1749 | } |
1737 | } | | 1750 | } |
1738 | | | 1751 | |
1739 | /* | | 1752 | /* |
1740 | * Note MEC chip seems to insert 2 byte padding at the top of | | 1753 | * Note MEC chip seems to insert 2 byte padding at the top of |
1741 | * RX buffer, but we copy whole buffer to avoid unaligned copy. | | 1754 | * RX buffer, but we copy whole buffer to avoid unaligned copy. |
1742 | */ | | 1755 | */ |
1743 | MEC_RXBUFSYNC(sc, i, len, BUS_DMASYNC_POSTREAD); | | 1756 | MEC_RXBUFSYNC(sc, i, len + ETHER_CRC_LEN, BUS_DMASYNC_POSTREAD); |
1744 | memcpy(mtod(m, void *), rxd->rxd_buf, MEC_ETHER_ALIGN + len); | | 1757 | memcpy(mtod(m, void *), rxd->rxd_buf, MEC_ETHER_ALIGN + len); |
| | | 1758 | crc = be32dec(rxd->rxd_buf + MEC_ETHER_ALIGN + len); |
1745 | MEC_RXBUFSYNC(sc, i, ETHER_MAX_LEN, BUS_DMASYNC_PREREAD); | | 1759 | MEC_RXBUFSYNC(sc, i, ETHER_MAX_LEN, BUS_DMASYNC_PREREAD); |
1746 | m->m_data += MEC_ETHER_ALIGN; | | 1760 | m->m_data += MEC_ETHER_ALIGN; |
1747 | | | 1761 | |
1748 | /* put RX buffer into FIFO again */ | | 1762 | /* put RX buffer into FIFO again */ |
1749 | rxd->rxd_stat = 0; | | 1763 | rxd->rxd_stat = 0; |
1750 | MEC_RXSTATSYNC(sc, i, BUS_DMASYNC_PREREAD); | | 1764 | MEC_RXSTATSYNC(sc, i, BUS_DMASYNC_PREREAD); |
1751 | bus_space_write_8(st, sh, MEC_MCL_RX_FIFO, MEC_CDRXADDR(sc, i)); | | 1765 | bus_space_write_8(st, sh, MEC_MCL_RX_FIFO, MEC_CDRXADDR(sc, i)); |
1752 | | | 1766 | |
1753 | m->m_pkthdr.rcvif = ifp; | | 1767 | m->m_pkthdr.rcvif = ifp; |
1754 | m->m_pkthdr.len = m->m_len = len; | | 1768 | m->m_pkthdr.len = m->m_len = len; |
| | | 1769 | if ((ifp->if_csum_flags_rx & (M_CSUM_TCPv4|M_CSUM_UDPv4)) != 0) |
| | | 1770 | mec_rxcsum(sc, m, RXSTAT_CKSUM(rxstat), crc); |
1755 | | | 1771 | |
1756 | ifp->if_ipackets++; | | 1772 | ifp->if_ipackets++; |
1757 | | | 1773 | |
1758 | #if NBPFILTER > 0 | | 1774 | #if NBPFILTER > 0 |
1759 | /* | | 1775 | /* |
1760 | * Pass this up to any BPF listeners, but only | | 1776 | * Pass this up to any BPF listeners, but only |
1761 | * pass it up the stack if it's for us. | | 1777 | * pass it up the stack if it's for us. |
1762 | */ | | 1778 | */ |
1763 | if (ifp->if_bpf) | | 1779 | if (ifp->if_bpf) |
1764 | bpf_mtap(ifp->if_bpf, m); | | 1780 | bpf_mtap(ifp->if_bpf, m); |
1765 | #endif | | 1781 | #endif |
1766 | | | 1782 | |
1767 | /* Pass it on. */ | | 1783 | /* Pass it on. */ |
1768 | (*ifp->if_input)(ifp, m); | | 1784 | (*ifp->if_input)(ifp, m); |
1769 | } | | 1785 | } |
1770 | | | 1786 | |
1771 | /* update RX pointer */ | | 1787 | /* update RX pointer */ |
1772 | sc->sc_rxptr = i; | | 1788 | sc->sc_rxptr = i; |
1773 | } | | 1789 | } |
1774 | | | 1790 | |
1775 | static void | | 1791 | static void |
| | | 1792 | mec_rxcsum(struct mec_softc *sc, struct mbuf *m, uint16_t rxcsum, uint32_t crc) |
| | | 1793 | { |
| | | 1794 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
| | | 1795 | struct ether_header *eh; |
| | | 1796 | struct ip *ip; |
| | | 1797 | struct udphdr *uh; |
| | | 1798 | u_int len, pktlen, hlen; |
| | | 1799 | uint32_t csum_data, dsum; |
| | | 1800 | int csum_flags; |
| | | 1801 | const uint16_t *dp; |
| | | 1802 | |
| | | 1803 | csum_data = 0; |
| | | 1804 | csum_flags = 0; |
| | | 1805 | |
| | | 1806 | len = m->m_len; |
| | | 1807 | if (len < ETHER_HDR_LEN + sizeof(struct ip)) |
| | | 1808 | goto out; |
| | | 1809 | pktlen = len - ETHER_HDR_LEN; |
| | | 1810 | eh = mtod(m, struct ether_header *); |
| | | 1811 | if (ntohs(eh->ether_type) != ETHERTYPE_IP) |
| | | 1812 | goto out; |
| | | 1813 | ip = (struct ip *)((uint8_t *)eh + ETHER_HDR_LEN); |
| | | 1814 | if (ip->ip_v != IPVERSION) |
| | | 1815 | goto out; |
| | | 1816 | |
| | | 1817 | hlen = ip->ip_hl << 2; |
| | | 1818 | if (hlen < sizeof(struct ip)) |
| | | 1819 | goto out; |
| | | 1820 | |
| | | 1821 | /* |
| | | 1822 | * Bail if too short, has random trailing garbage, truncated, |
| | | 1823 | * fragment, or has ethernet pad. |
| | | 1824 | */ |
| | | 1825 | if (ntohs(ip->ip_len) < hlen || |
| | | 1826 | ntohs(ip->ip_len) != pktlen || |
| | | 1827 | (ntohs(ip->ip_off) & (IP_MF | IP_OFFMASK)) != 0) |
| | | 1828 | goto out; |
| | | 1829 | |
| | | 1830 | switch (ip->ip_p) { |
| | | 1831 | case IPPROTO_TCP: |
| | | 1832 | if ((ifp->if_csum_flags_rx & M_CSUM_TCPv4) == 0 || |
| | | 1833 | pktlen < (hlen + sizeof(struct tcphdr))) |
| | | 1834 | goto out; |
| | | 1835 | csum_flags = M_CSUM_TCPv4 | M_CSUM_DATA | M_CSUM_NO_PSEUDOHDR; |
| | | 1836 | break; |
| | | 1837 | case IPPROTO_UDP: |
| | | 1838 | if ((ifp->if_csum_flags_rx & M_CSUM_UDPv4) == 0 || |
| | | 1839 | pktlen < (hlen + sizeof(struct udphdr))) |
| | | 1840 | goto out; |
| | | 1841 | uh = (struct udphdr *)((uint8_t *)ip + hlen); |
| | | 1842 | if (uh->uh_sum == 0) |
| | | 1843 | goto out; /* no checksum */ |
| | | 1844 | csum_flags = M_CSUM_UDPv4 | M_CSUM_DATA | M_CSUM_NO_PSEUDOHDR; |
| | | 1845 | break; |
| | | 1846 | default: |
| | | 1847 | goto out; |
| | | 1848 | } |
| | | 1849 | |
| | | 1850 | /* |
| | | 1851 | * The computed checksum includes Ethernet header, IP headers, |
| | | 1852 | * and CRC, so we have to deduct them. |
| | | 1853 | * Note IP header cksum should be 0xffff so we don't have to |
| | | 1854 | * dedecut them. |
| | | 1855 | */ |
| | | 1856 | dsum = 0; |
| | | 1857 | |
| | | 1858 | /* deduct Ethernet header */ |
| | | 1859 | dp = (const uint16_t *)eh; |
| | | 1860 | for (hlen = 0; hlen < (ETHER_HDR_LEN / sizeof(uint16_t)); hlen++) |
| | | 1861 | dsum += ntohs(*dp++); |
| | | 1862 | |
| | | 1863 | /* deduct CRC */ |
| | | 1864 | if (len & 1) { |
| | | 1865 | dsum += (crc >> 24) & 0x00ff; |
| | | 1866 | dsum += (crc >> 8) & 0xffff; |
| | | 1867 | dsum += (crc << 8) & 0xff00; |
| | | 1868 | } else { |
| | | 1869 | dsum += (crc >> 16) & 0xffff; |
| | | 1870 | dsum += (crc >> 0) & 0xffff; |
| | | 1871 | } |
| | | 1872 | while (dsum >> 16) |
| | | 1873 | dsum = (dsum >> 16) + (dsum & 0xffff); |
| | | 1874 | |
| | | 1875 | csum_data = rxcsum; |
| | | 1876 | csum_data += (uint16_t)~dsum; |
| | | 1877 | |
| | | 1878 | while (csum_data >> 16) |
| | | 1879 | csum_data = (csum_data >> 16) + (csum_data & 0xffff); |
| | | 1880 | |
| | | 1881 | out: |
| | | 1882 | m->m_pkthdr.csum_flags = csum_flags; |
| | | 1883 | m->m_pkthdr.csum_data = csum_data; |
| | | 1884 | } |
| | | 1885 | |
| | | 1886 | static void |
1776 | mec_txintr(struct mec_softc *sc, uint32_t txptr) | | 1887 | mec_txintr(struct mec_softc *sc, uint32_t txptr) |
1777 | { | | 1888 | { |
1778 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | | 1889 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
1779 | struct mec_txdesc *txd; | | 1890 | struct mec_txdesc *txd; |
1780 | struct mec_txsoft *txs; | | 1891 | struct mec_txsoft *txs; |
1781 | bus_dmamap_t dmamap; | | 1892 | bus_dmamap_t dmamap; |
1782 | uint64_t txstat; | | 1893 | uint64_t txstat; |
1783 | int i; | | 1894 | int i; |
1784 | u_int col; | | 1895 | u_int col; |
1785 | | | 1896 | |
1786 | DPRINTF(MEC_DEBUG_TXINTR, ("mec_txintr: called\n")); | | 1897 | DPRINTF(MEC_DEBUG_TXINTR, ("mec_txintr: called\n")); |
1787 | | | 1898 | |
1788 | for (i = sc->sc_txdirty; i != txptr && sc->sc_txpending != 0; | | 1899 | for (i = sc->sc_txdirty; i != txptr && sc->sc_txpending != 0; |