| @@ -1,1261 +1,1263 @@ | | | @@ -1,1261 +1,1263 @@ |
1 | /* $NetBSD: dp83932.c,v 1.35 2010/11/13 13:52:00 uebayasi Exp $ */ | | 1 | /* $NetBSD: dp83932.c,v 1.35.14.1 2017/08/18 15:04:58 snj Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2001 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2001 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Jason R. Thorpe. | | 8 | * by Jason R. Thorpe. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * Device driver for the National Semiconductor DP83932 | | 33 | * Device driver for the National Semiconductor DP83932 |
34 | * Systems-Oriented Network Interface Controller (SONIC). | | 34 | * Systems-Oriented Network Interface Controller (SONIC). |
35 | */ | | 35 | */ |
36 | | | 36 | |
37 | #include <sys/cdefs.h> | | 37 | #include <sys/cdefs.h> |
38 | __KERNEL_RCSID(0, "$NetBSD: dp83932.c,v 1.35 2010/11/13 13:52:00 uebayasi Exp $"); | | 38 | __KERNEL_RCSID(0, "$NetBSD: dp83932.c,v 1.35.14.1 2017/08/18 15:04:58 snj Exp $"); |
39 | | | 39 | |
40 | | | 40 | |
41 | #include <sys/param.h> | | 41 | #include <sys/param.h> |
42 | #include <sys/systm.h> | | 42 | #include <sys/systm.h> |
43 | #include <sys/mbuf.h> | | 43 | #include <sys/mbuf.h> |
44 | #include <sys/malloc.h> | | 44 | #include <sys/malloc.h> |
45 | #include <sys/kernel.h> | | 45 | #include <sys/kernel.h> |
46 | #include <sys/socket.h> | | 46 | #include <sys/socket.h> |
47 | #include <sys/ioctl.h> | | 47 | #include <sys/ioctl.h> |
48 | #include <sys/errno.h> | | 48 | #include <sys/errno.h> |
49 | #include <sys/device.h> | | 49 | #include <sys/device.h> |
50 | | | 50 | |
51 | #include <net/if.h> | | 51 | #include <net/if.h> |
52 | #include <net/if_dl.h> | | 52 | #include <net/if_dl.h> |
53 | #include <net/if_ether.h> | | 53 | #include <net/if_ether.h> |
54 | | | 54 | |
55 | #include <net/bpf.h> | | 55 | #include <net/bpf.h> |
56 | | | 56 | |
57 | #include <sys/bus.h> | | 57 | #include <sys/bus.h> |
58 | #include <sys/intr.h> | | 58 | #include <sys/intr.h> |
59 | | | 59 | |
60 | #include <dev/ic/dp83932reg.h> | | 60 | #include <dev/ic/dp83932reg.h> |
61 | #include <dev/ic/dp83932var.h> | | 61 | #include <dev/ic/dp83932var.h> |
62 | | | 62 | |
63 | static void sonic_start(struct ifnet *); | | 63 | static void sonic_start(struct ifnet *); |
64 | static void sonic_watchdog(struct ifnet *); | | 64 | static void sonic_watchdog(struct ifnet *); |
65 | static int sonic_ioctl(struct ifnet *, u_long, void *); | | 65 | static int sonic_ioctl(struct ifnet *, u_long, void *); |
66 | static int sonic_init(struct ifnet *); | | 66 | static int sonic_init(struct ifnet *); |
67 | static void sonic_stop(struct ifnet *, int); | | 67 | static void sonic_stop(struct ifnet *, int); |
68 | | | 68 | |
69 | static bool sonic_shutdown(device_t, int); | | 69 | static bool sonic_shutdown(device_t, int); |
70 | | | 70 | |
71 | static void sonic_reset(struct sonic_softc *); | | 71 | static void sonic_reset(struct sonic_softc *); |
72 | static void sonic_rxdrain(struct sonic_softc *); | | 72 | static void sonic_rxdrain(struct sonic_softc *); |
73 | static int sonic_add_rxbuf(struct sonic_softc *, int); | | 73 | static int sonic_add_rxbuf(struct sonic_softc *, int); |
74 | static void sonic_set_filter(struct sonic_softc *); | | 74 | static void sonic_set_filter(struct sonic_softc *); |
75 | | | 75 | |
76 | static uint16_t sonic_txintr(struct sonic_softc *); | | 76 | static uint16_t sonic_txintr(struct sonic_softc *); |
77 | static void sonic_rxintr(struct sonic_softc *); | | 77 | static void sonic_rxintr(struct sonic_softc *); |
78 | | | 78 | |
79 | int sonic_copy_small = 0; | | 79 | int sonic_copy_small = 0; |
80 | | | 80 | |
81 | #define ETHER_PAD_LEN (ETHER_MIN_LEN - ETHER_CRC_LEN) | | 81 | #define ETHER_PAD_LEN (ETHER_MIN_LEN - ETHER_CRC_LEN) |
82 | | | 82 | |
83 | /* | | 83 | /* |
84 | * sonic_attach: | | 84 | * sonic_attach: |
85 | * | | 85 | * |
86 | * Attach a SONIC interface to the system. | | 86 | * Attach a SONIC interface to the system. |
87 | */ | | 87 | */ |
88 | void | | 88 | void |
89 | sonic_attach(struct sonic_softc *sc, const uint8_t *enaddr) | | 89 | sonic_attach(struct sonic_softc *sc, const uint8_t *enaddr) |
90 | { | | 90 | { |
91 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | | 91 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
92 | int i, rseg, error; | | 92 | int i, rseg, error; |
93 | bus_dma_segment_t seg; | | 93 | bus_dma_segment_t seg; |
94 | size_t cdatasize; | | 94 | size_t cdatasize; |
95 | uint8_t *nullbuf; | | 95 | uint8_t *nullbuf; |
96 | | | 96 | |
97 | /* | | 97 | /* |
98 | * Allocate the control data structures, and create and load the | | 98 | * Allocate the control data structures, and create and load the |
99 | * DMA map for it. | | 99 | * DMA map for it. |
100 | */ | | 100 | */ |
101 | if (sc->sc_32bit) | | 101 | if (sc->sc_32bit) |
102 | cdatasize = sizeof(struct sonic_control_data32); | | 102 | cdatasize = sizeof(struct sonic_control_data32); |
103 | else | | 103 | else |
104 | cdatasize = sizeof(struct sonic_control_data16); | | 104 | cdatasize = sizeof(struct sonic_control_data16); |
105 | | | 105 | |
106 | if ((error = bus_dmamem_alloc(sc->sc_dmat, cdatasize + ETHER_PAD_LEN, | | 106 | if ((error = bus_dmamem_alloc(sc->sc_dmat, cdatasize + ETHER_PAD_LEN, |
107 | PAGE_SIZE, (64 * 1024), &seg, 1, &rseg, | | 107 | PAGE_SIZE, (64 * 1024), &seg, 1, &rseg, |
108 | BUS_DMA_NOWAIT)) != 0) { | | 108 | BUS_DMA_NOWAIT)) != 0) { |
109 | aprint_error_dev(sc->sc_dev, | | 109 | aprint_error_dev(sc->sc_dev, |
110 | "unable to allocate control data, error = %d\n", error); | | 110 | "unable to allocate control data, error = %d\n", error); |
111 | goto fail_0; | | 111 | goto fail_0; |
112 | } | | 112 | } |
113 | | | 113 | |
114 | if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, | | 114 | if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, |
115 | cdatasize + ETHER_PAD_LEN, (void **) &sc->sc_cdata16, | | 115 | cdatasize + ETHER_PAD_LEN, (void **) &sc->sc_cdata16, |
116 | BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) { | | 116 | BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) { |
117 | aprint_error_dev(sc->sc_dev, | | 117 | aprint_error_dev(sc->sc_dev, |
118 | "unable to map control data, error = %d\n", error); | | 118 | "unable to map control data, error = %d\n", error); |
119 | goto fail_1; | | 119 | goto fail_1; |
120 | } | | 120 | } |
121 | nullbuf = (uint8_t *)sc->sc_cdata16 + cdatasize; | | 121 | nullbuf = (uint8_t *)sc->sc_cdata16 + cdatasize; |
122 | memset(nullbuf, 0, ETHER_PAD_LEN); | | 122 | memset(nullbuf, 0, ETHER_PAD_LEN); |
123 | | | 123 | |
124 | if ((error = bus_dmamap_create(sc->sc_dmat, | | 124 | if ((error = bus_dmamap_create(sc->sc_dmat, |
125 | cdatasize, 1, cdatasize, 0, BUS_DMA_NOWAIT, | | 125 | cdatasize, 1, cdatasize, 0, BUS_DMA_NOWAIT, |
126 | &sc->sc_cddmamap)) != 0) { | | 126 | &sc->sc_cddmamap)) != 0) { |
127 | aprint_error_dev(sc->sc_dev, | | 127 | aprint_error_dev(sc->sc_dev, |
128 | "unable to create control data DMA map, error = %d\n", | | 128 | "unable to create control data DMA map, error = %d\n", |
129 | error); | | 129 | error); |
130 | goto fail_2; | | 130 | goto fail_2; |
131 | } | | 131 | } |
132 | | | 132 | |
133 | if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_cddmamap, | | 133 | if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_cddmamap, |
134 | sc->sc_cdata16, cdatasize, NULL, BUS_DMA_NOWAIT)) != 0) { | | 134 | sc->sc_cdata16, cdatasize, NULL, BUS_DMA_NOWAIT)) != 0) { |
135 | aprint_error_dev(sc->sc_dev, | | 135 | aprint_error_dev(sc->sc_dev, |
136 | "unable to load control data DMA map, error = %d\n", error); | | 136 | "unable to load control data DMA map, error = %d\n", error); |
137 | goto fail_3; | | 137 | goto fail_3; |
138 | } | | 138 | } |
139 | | | 139 | |
140 | /* | | 140 | /* |
141 | * Create the transmit buffer DMA maps. | | 141 | * Create the transmit buffer DMA maps. |
142 | */ | | 142 | */ |
143 | for (i = 0; i < SONIC_NTXDESC; i++) { | | 143 | for (i = 0; i < SONIC_NTXDESC; i++) { |
144 | if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, | | 144 | if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, |
145 | SONIC_NTXFRAGS, MCLBYTES, 0, BUS_DMA_NOWAIT, | | 145 | SONIC_NTXFRAGS, MCLBYTES, 0, BUS_DMA_NOWAIT, |
146 | &sc->sc_txsoft[i].ds_dmamap)) != 0) { | | 146 | &sc->sc_txsoft[i].ds_dmamap)) != 0) { |
147 | aprint_error_dev(sc->sc_dev, | | 147 | aprint_error_dev(sc->sc_dev, |
148 | "unable to create tx DMA map %d, error = %d\n", | | 148 | "unable to create tx DMA map %d, error = %d\n", |
149 | i, error); | | 149 | i, error); |
150 | goto fail_4; | | 150 | goto fail_4; |
151 | } | | 151 | } |
152 | } | | 152 | } |
153 | | | 153 | |
154 | /* | | 154 | /* |
155 | * Create the receive buffer DMA maps. | | 155 | * Create the receive buffer DMA maps. |
156 | */ | | 156 | */ |
157 | for (i = 0; i < SONIC_NRXDESC; i++) { | | 157 | for (i = 0; i < SONIC_NRXDESC; i++) { |
158 | if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, | | 158 | if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, |
159 | MCLBYTES, 0, BUS_DMA_NOWAIT, | | 159 | MCLBYTES, 0, BUS_DMA_NOWAIT, |
160 | &sc->sc_rxsoft[i].ds_dmamap)) != 0) { | | 160 | &sc->sc_rxsoft[i].ds_dmamap)) != 0) { |
161 | aprint_error_dev(sc->sc_dev, | | 161 | aprint_error_dev(sc->sc_dev, |
162 | "unable to create rx DMA map %d, error = %d\n", | | 162 | "unable to create rx DMA map %d, error = %d\n", |
163 | i, error); | | 163 | i, error); |
164 | goto fail_5; | | 164 | goto fail_5; |
165 | } | | 165 | } |
166 | sc->sc_rxsoft[i].ds_mbuf = NULL; | | 166 | sc->sc_rxsoft[i].ds_mbuf = NULL; |
167 | } | | 167 | } |
168 | | | 168 | |
169 | /* | | 169 | /* |
170 | * create and map the pad buffer | | 170 | * create and map the pad buffer |
171 | */ | | 171 | */ |
172 | if ((error = bus_dmamap_create(sc->sc_dmat, ETHER_PAD_LEN, 1, | | 172 | if ((error = bus_dmamap_create(sc->sc_dmat, ETHER_PAD_LEN, 1, |
173 | ETHER_PAD_LEN, 0, BUS_DMA_NOWAIT, &sc->sc_nulldmamap)) != 0) { | | 173 | ETHER_PAD_LEN, 0, BUS_DMA_NOWAIT, &sc->sc_nulldmamap)) != 0) { |
174 | aprint_error_dev(sc->sc_dev, | | 174 | aprint_error_dev(sc->sc_dev, |
175 | "unable to create pad buffer DMA map, error = %d\n", error); | | 175 | "unable to create pad buffer DMA map, error = %d\n", error); |
176 | goto fail_5; | | 176 | goto fail_5; |
177 | } | | 177 | } |
178 | | | 178 | |
179 | if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_nulldmamap, | | 179 | if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_nulldmamap, |
180 | nullbuf, ETHER_PAD_LEN, NULL, BUS_DMA_NOWAIT)) != 0) { | | 180 | nullbuf, ETHER_PAD_LEN, NULL, BUS_DMA_NOWAIT)) != 0) { |
181 | aprint_error_dev(sc->sc_dev, | | 181 | aprint_error_dev(sc->sc_dev, |
182 | "unable to load pad buffer DMA map, error = %d\n", error); | | 182 | "unable to load pad buffer DMA map, error = %d\n", error); |
183 | goto fail_6; | | 183 | goto fail_6; |
184 | } | | 184 | } |
185 | bus_dmamap_sync(sc->sc_dmat, sc->sc_nulldmamap, 0, ETHER_PAD_LEN, | | 185 | bus_dmamap_sync(sc->sc_dmat, sc->sc_nulldmamap, 0, ETHER_PAD_LEN, |
186 | BUS_DMASYNC_PREWRITE); | | 186 | BUS_DMASYNC_PREWRITE); |
187 | | | 187 | |
188 | /* | | 188 | /* |
189 | * Reset the chip to a known state. | | 189 | * Reset the chip to a known state. |
190 | */ | | 190 | */ |
191 | sonic_reset(sc); | | 191 | sonic_reset(sc); |
192 | | | 192 | |
193 | aprint_normal_dev(sc->sc_dev, "Ethernet address %s\n", | | 193 | aprint_normal_dev(sc->sc_dev, "Ethernet address %s\n", |
194 | ether_sprintf(enaddr)); | | 194 | ether_sprintf(enaddr)); |
195 | | | 195 | |
196 | strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); | | 196 | strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); |
197 | ifp->if_softc = sc; | | 197 | ifp->if_softc = sc; |
198 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | | 198 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; |
199 | ifp->if_ioctl = sonic_ioctl; | | 199 | ifp->if_ioctl = sonic_ioctl; |
200 | ifp->if_start = sonic_start; | | 200 | ifp->if_start = sonic_start; |
201 | ifp->if_watchdog = sonic_watchdog; | | 201 | ifp->if_watchdog = sonic_watchdog; |
202 | ifp->if_init = sonic_init; | | 202 | ifp->if_init = sonic_init; |
203 | ifp->if_stop = sonic_stop; | | 203 | ifp->if_stop = sonic_stop; |
204 | IFQ_SET_READY(&ifp->if_snd); | | 204 | IFQ_SET_READY(&ifp->if_snd); |
205 | | | 205 | |
206 | /* | | 206 | /* |
207 | * We can support 802.1Q VLAN-sized frames. | | 207 | * We can support 802.1Q VLAN-sized frames. |
208 | */ | | 208 | */ |
209 | sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU; | | 209 | sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU; |
210 | | | 210 | |
211 | /* | | 211 | /* |
212 | * Attach the interface. | | 212 | * Attach the interface. |
213 | */ | | 213 | */ |
214 | if_attach(ifp); | | 214 | if_attach(ifp); |
215 | ether_ifattach(ifp, enaddr); | | 215 | ether_ifattach(ifp, enaddr); |
216 | | | 216 | |
217 | /* | | 217 | /* |
218 | * Make sure the interface is shutdown during reboot. | | 218 | * Make sure the interface is shutdown during reboot. |
219 | */ | | 219 | */ |
220 | if (pmf_device_register1(sc->sc_dev, NULL, NULL, sonic_shutdown)) | | 220 | if (pmf_device_register1(sc->sc_dev, NULL, NULL, sonic_shutdown)) |
221 | pmf_class_network_register(sc->sc_dev, ifp); | | 221 | pmf_class_network_register(sc->sc_dev, ifp); |
222 | else | | 222 | else |
223 | aprint_error_dev(sc->sc_dev, | | 223 | aprint_error_dev(sc->sc_dev, |
224 | "couldn't establish power handler\n"); | | 224 | "couldn't establish power handler\n"); |
225 | | | 225 | |
226 | return; | | 226 | return; |
227 | | | 227 | |
228 | /* | | 228 | /* |
229 | * Free any resources we've allocated during the failed attach | | 229 | * Free any resources we've allocated during the failed attach |
230 | * attempt. Do this in reverse order and fall through. | | 230 | * attempt. Do this in reverse order and fall through. |
231 | */ | | 231 | */ |
232 | fail_6: | | 232 | fail_6: |
233 | bus_dmamap_destroy(sc->sc_dmat, sc->sc_nulldmamap); | | 233 | bus_dmamap_destroy(sc->sc_dmat, sc->sc_nulldmamap); |
234 | fail_5: | | 234 | fail_5: |
235 | for (i = 0; i < SONIC_NRXDESC; i++) { | | 235 | for (i = 0; i < SONIC_NRXDESC; i++) { |
236 | if (sc->sc_rxsoft[i].ds_dmamap != NULL) | | 236 | if (sc->sc_rxsoft[i].ds_dmamap != NULL) |
237 | bus_dmamap_destroy(sc->sc_dmat, | | 237 | bus_dmamap_destroy(sc->sc_dmat, |
238 | sc->sc_rxsoft[i].ds_dmamap); | | 238 | sc->sc_rxsoft[i].ds_dmamap); |
239 | } | | 239 | } |
240 | fail_4: | | 240 | fail_4: |
241 | for (i = 0; i < SONIC_NTXDESC; i++) { | | 241 | for (i = 0; i < SONIC_NTXDESC; i++) { |
242 | if (sc->sc_txsoft[i].ds_dmamap != NULL) | | 242 | if (sc->sc_txsoft[i].ds_dmamap != NULL) |
243 | bus_dmamap_destroy(sc->sc_dmat, | | 243 | bus_dmamap_destroy(sc->sc_dmat, |
244 | sc->sc_txsoft[i].ds_dmamap); | | 244 | sc->sc_txsoft[i].ds_dmamap); |
245 | } | | 245 | } |
246 | bus_dmamap_unload(sc->sc_dmat, sc->sc_cddmamap); | | 246 | bus_dmamap_unload(sc->sc_dmat, sc->sc_cddmamap); |
247 | fail_3: | | 247 | fail_3: |
248 | bus_dmamap_destroy(sc->sc_dmat, sc->sc_cddmamap); | | 248 | bus_dmamap_destroy(sc->sc_dmat, sc->sc_cddmamap); |
249 | fail_2: | | 249 | fail_2: |
250 | bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_cdata16, cdatasize); | | 250 | bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_cdata16, cdatasize); |
251 | fail_1: | | 251 | fail_1: |
252 | bus_dmamem_free(sc->sc_dmat, &seg, rseg); | | 252 | bus_dmamem_free(sc->sc_dmat, &seg, rseg); |
253 | fail_0: | | 253 | fail_0: |
254 | return; | | 254 | return; |
255 | } | | 255 | } |
256 | | | 256 | |
257 | /* | | 257 | /* |
258 | * sonic_shutdown: | | 258 | * sonic_shutdown: |
259 | * | | 259 | * |
260 | * Make sure the interface is stopped at reboot. | | 260 | * Make sure the interface is stopped at reboot. |
261 | */ | | 261 | */ |
262 | bool | | 262 | bool |
263 | sonic_shutdown(device_t self, int howto) | | 263 | sonic_shutdown(device_t self, int howto) |
264 | { | | 264 | { |
265 | struct sonic_softc *sc = device_private(self); | | 265 | struct sonic_softc *sc = device_private(self); |
266 | | | 266 | |
267 | sonic_stop(&sc->sc_ethercom.ec_if, 1); | | 267 | sonic_stop(&sc->sc_ethercom.ec_if, 1); |
268 | | | 268 | |
269 | return true; | | 269 | return true; |
270 | } | | 270 | } |
271 | | | 271 | |
272 | /* | | 272 | /* |
273 | * sonic_start: [ifnet interface function] | | 273 | * sonic_start: [ifnet interface function] |
274 | * | | 274 | * |
275 | * Start packet transmission on the interface. | | 275 | * Start packet transmission on the interface. |
276 | */ | | 276 | */ |
277 | void | | 277 | void |
278 | sonic_start(struct ifnet *ifp) | | 278 | sonic_start(struct ifnet *ifp) |
279 | { | | 279 | { |
280 | struct sonic_softc *sc = ifp->if_softc; | | 280 | struct sonic_softc *sc = ifp->if_softc; |
281 | struct mbuf *m0, *m; | | 281 | struct mbuf *m0, *m; |
282 | struct sonic_tda16 *tda16; | | 282 | struct sonic_tda16 *tda16; |
283 | struct sonic_tda32 *tda32; | | 283 | struct sonic_tda32 *tda32; |
284 | struct sonic_descsoft *ds; | | 284 | struct sonic_descsoft *ds; |
285 | bus_dmamap_t dmamap; | | 285 | bus_dmamap_t dmamap; |
286 | int error, olasttx, nexttx, opending, totlen, olseg; | | 286 | int error, olasttx, nexttx, opending, totlen, olseg; |
287 | int seg = 0; /* XXX: gcc */ | | 287 | int seg = 0; /* XXX: gcc */ |
288 | | | 288 | |
289 | if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING) | | 289 | if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING) |
290 | return; | | 290 | return; |
291 | | | 291 | |
292 | /* | | 292 | /* |
293 | * Remember the previous txpending and the current "last txdesc | | 293 | * Remember the previous txpending and the current "last txdesc |
294 | * used" index. | | 294 | * used" index. |
295 | */ | | 295 | */ |
296 | opending = sc->sc_txpending; | | 296 | opending = sc->sc_txpending; |
297 | olasttx = sc->sc_txlast; | | 297 | olasttx = sc->sc_txlast; |
298 | | | 298 | |
299 | /* | | 299 | /* |
300 | * Loop through the send queue, setting up transmit descriptors | | 300 | * Loop through the send queue, setting up transmit descriptors |
301 | * until we drain the queue, or use up all available transmit | | 301 | * until we drain the queue, or use up all available transmit |
302 | * descriptors. Leave one at the end for sanity's sake. | | 302 | * descriptors. Leave one at the end for sanity's sake. |
303 | */ | | 303 | */ |
304 | while (sc->sc_txpending < (SONIC_NTXDESC - 1)) { | | 304 | while (sc->sc_txpending < (SONIC_NTXDESC - 1)) { |
305 | /* | | 305 | /* |
306 | * Grab a packet off the queue. | | 306 | * Grab a packet off the queue. |
307 | */ | | 307 | */ |
308 | IFQ_POLL(&ifp->if_snd, m0); | | 308 | IFQ_POLL(&ifp->if_snd, m0); |
309 | if (m0 == NULL) | | 309 | if (m0 == NULL) |
310 | break; | | 310 | break; |
311 | m = NULL; | | 311 | m = NULL; |
312 | | | 312 | |
313 | /* | | 313 | /* |
314 | * Get the next available transmit descriptor. | | 314 | * Get the next available transmit descriptor. |
315 | */ | | 315 | */ |
316 | nexttx = SONIC_NEXTTX(sc->sc_txlast); | | 316 | nexttx = SONIC_NEXTTX(sc->sc_txlast); |
317 | ds = &sc->sc_txsoft[nexttx]; | | 317 | ds = &sc->sc_txsoft[nexttx]; |
318 | dmamap = ds->ds_dmamap; | | 318 | dmamap = ds->ds_dmamap; |
319 | | | 319 | |
320 | /* | | 320 | /* |
321 | * Load the DMA map. If this fails, the packet either | | 321 | * Load the DMA map. If this fails, the packet either |
322 | * didn't fit in the allotted number of frags, or we were | | 322 | * didn't fit in the allotted number of frags, or we were |
323 | * short on resources. In this case, we'll copy and try | | 323 | * short on resources. In this case, we'll copy and try |
324 | * again. | | 324 | * again. |
325 | */ | | 325 | */ |
326 | if ((error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0, | | 326 | if ((error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0, |
327 | BUS_DMA_WRITE|BUS_DMA_NOWAIT)) != 0 || | | 327 | BUS_DMA_WRITE|BUS_DMA_NOWAIT)) != 0 || |
328 | (m0->m_pkthdr.len < ETHER_PAD_LEN && | | 328 | (m0->m_pkthdr.len < ETHER_PAD_LEN && |
329 | dmamap->dm_nsegs == SONIC_NTXFRAGS)) { | | 329 | dmamap->dm_nsegs == SONIC_NTXFRAGS)) { |
330 | if (error == 0) | | 330 | if (error == 0) |
331 | bus_dmamap_unload(sc->sc_dmat, dmamap); | | 331 | bus_dmamap_unload(sc->sc_dmat, dmamap); |
332 | MGETHDR(m, M_DONTWAIT, MT_DATA); | | 332 | MGETHDR(m, M_DONTWAIT, MT_DATA); |
333 | if (m == NULL) { | | 333 | if (m == NULL) { |
334 | printf("%s: unable to allocate Tx mbuf\n", | | 334 | printf("%s: unable to allocate Tx mbuf\n", |
335 | device_xname(sc->sc_dev)); | | 335 | device_xname(sc->sc_dev)); |
336 | break; | | 336 | break; |
337 | } | | 337 | } |
338 | if (m0->m_pkthdr.len > MHLEN) { | | 338 | if (m0->m_pkthdr.len > MHLEN) { |
339 | MCLGET(m, M_DONTWAIT); | | 339 | MCLGET(m, M_DONTWAIT); |
340 | if ((m->m_flags & M_EXT) == 0) { | | 340 | if ((m->m_flags & M_EXT) == 0) { |
341 | printf("%s: unable to allocate Tx " | | 341 | printf("%s: unable to allocate Tx " |
342 | "cluster\n", | | 342 | "cluster\n", |
343 | device_xname(sc->sc_dev)); | | 343 | device_xname(sc->sc_dev)); |
344 | m_freem(m); | | 344 | m_freem(m); |
345 | break; | | 345 | break; |
346 | } | | 346 | } |
347 | } | | 347 | } |
348 | m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, void *)); | | 348 | m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, void *)); |
349 | m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len; | | 349 | m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len; |
350 | error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, | | 350 | error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, |
351 | m, BUS_DMA_WRITE|BUS_DMA_NOWAIT); | | 351 | m, BUS_DMA_WRITE|BUS_DMA_NOWAIT); |
352 | if (error) { | | 352 | if (error) { |
353 | printf("%s: unable to load Tx buffer, " | | 353 | printf("%s: unable to load Tx buffer, " |
354 | "error = %d\n", device_xname(sc->sc_dev), | | 354 | "error = %d\n", device_xname(sc->sc_dev), |
355 | error); | | 355 | error); |
356 | m_freem(m); | | 356 | m_freem(m); |
357 | break; | | 357 | break; |
358 | } | | 358 | } |
359 | } | | 359 | } |
360 | IFQ_DEQUEUE(&ifp->if_snd, m0); | | 360 | IFQ_DEQUEUE(&ifp->if_snd, m0); |
361 | if (m != NULL) { | | 361 | if (m != NULL) { |
362 | m_freem(m0); | | 362 | m_freem(m0); |
363 | m0 = m; | | 363 | m0 = m; |
364 | } | | 364 | } |
365 | | | 365 | |
366 | /* | | 366 | /* |
367 | * WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET. | | 367 | * WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET. |
368 | */ | | 368 | */ |
369 | | | 369 | |
370 | /* Sync the DMA map. */ | | 370 | /* Sync the DMA map. */ |
371 | bus_dmamap_sync(sc->sc_dmat, dmamap, 0, dmamap->dm_mapsize, | | 371 | bus_dmamap_sync(sc->sc_dmat, dmamap, 0, dmamap->dm_mapsize, |
372 | BUS_DMASYNC_PREWRITE); | | 372 | BUS_DMASYNC_PREWRITE); |
373 | | | 373 | |
374 | /* | | 374 | /* |
375 | * Store a pointer to the packet so we can free it later. | | 375 | * Store a pointer to the packet so we can free it later. |
376 | */ | | 376 | */ |
377 | ds->ds_mbuf = m0; | | 377 | ds->ds_mbuf = m0; |
378 | | | 378 | |
379 | /* | | 379 | /* |
380 | * Initialize the transmit descriptor. | | 380 | * Initialize the transmit descriptor. |
381 | */ | | 381 | */ |
382 | totlen = 0; | | 382 | totlen = 0; |
383 | if (sc->sc_32bit) { | | 383 | if (sc->sc_32bit) { |
384 | tda32 = &sc->sc_tda32[nexttx]; | | 384 | tda32 = &sc->sc_tda32[nexttx]; |
385 | for (seg = 0; seg < dmamap->dm_nsegs; seg++) { | | 385 | for (seg = 0; seg < dmamap->dm_nsegs; seg++) { |
386 | tda32->tda_frags[seg].frag_ptr1 = | | 386 | tda32->tda_frags[seg].frag_ptr1 = |
387 | htosonic32(sc, | | 387 | htosonic32(sc, |
388 | (dmamap->dm_segs[seg].ds_addr >> 16) & | | 388 | (dmamap->dm_segs[seg].ds_addr >> 16) & |
389 | 0xffff); | | 389 | 0xffff); |
390 | tda32->tda_frags[seg].frag_ptr0 = | | 390 | tda32->tda_frags[seg].frag_ptr0 = |
391 | htosonic32(sc, | | 391 | htosonic32(sc, |
392 | dmamap->dm_segs[seg].ds_addr & 0xffff); | | 392 | dmamap->dm_segs[seg].ds_addr & 0xffff); |
393 | tda32->tda_frags[seg].frag_size = | | 393 | tda32->tda_frags[seg].frag_size = |
394 | htosonic32(sc, dmamap->dm_segs[seg].ds_len); | | 394 | htosonic32(sc, dmamap->dm_segs[seg].ds_len); |
395 | totlen += dmamap->dm_segs[seg].ds_len; | | 395 | totlen += dmamap->dm_segs[seg].ds_len; |
396 | } | | 396 | } |
397 | if (totlen < ETHER_PAD_LEN) { | | 397 | if (totlen < ETHER_PAD_LEN) { |
398 | tda32->tda_frags[seg].frag_ptr1 = | | 398 | tda32->tda_frags[seg].frag_ptr1 = |
399 | htosonic32(sc, | | 399 | htosonic32(sc, |
400 | (sc->sc_nulldma >> 16) & 0xffff); | | 400 | (sc->sc_nulldma >> 16) & 0xffff); |
401 | tda32->tda_frags[seg].frag_ptr0 = | | 401 | tda32->tda_frags[seg].frag_ptr0 = |
402 | htosonic32(sc, sc->sc_nulldma & 0xffff); | | 402 | htosonic32(sc, sc->sc_nulldma & 0xffff); |
403 | tda32->tda_frags[seg].frag_size = | | 403 | tda32->tda_frags[seg].frag_size = |
404 | htosonic32(sc, ETHER_PAD_LEN - totlen); | | 404 | htosonic32(sc, ETHER_PAD_LEN - totlen); |
405 | totlen = ETHER_PAD_LEN; | | 405 | totlen = ETHER_PAD_LEN; |
406 | seg++; | | 406 | seg++; |
407 | } | | 407 | } |
408 | | | 408 | |
409 | tda32->tda_status = 0; | | 409 | tda32->tda_status = 0; |
410 | tda32->tda_pktconfig = 0; | | 410 | tda32->tda_pktconfig = 0; |
411 | tda32->tda_pktsize = htosonic32(sc, totlen); | | 411 | tda32->tda_pktsize = htosonic32(sc, totlen); |
412 | tda32->tda_fragcnt = htosonic32(sc, seg); | | 412 | tda32->tda_fragcnt = htosonic32(sc, seg); |
413 | | | 413 | |
414 | /* Link it up. */ | | 414 | /* Link it up. */ |
415 | tda32->tda_frags[seg].frag_ptr0 = | | 415 | tda32->tda_frags[seg].frag_ptr0 = |
416 | htosonic32(sc, SONIC_CDTXADDR32(sc, | | 416 | htosonic32(sc, SONIC_CDTXADDR32(sc, |
417 | SONIC_NEXTTX(nexttx)) & 0xffff); | | 417 | SONIC_NEXTTX(nexttx)) & 0xffff); |
418 | | | 418 | |
419 | /* Sync the Tx descriptor. */ | | 419 | /* Sync the Tx descriptor. */ |
420 | SONIC_CDTXSYNC32(sc, nexttx, | | 420 | SONIC_CDTXSYNC32(sc, nexttx, |
421 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); | | 421 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); |
422 | } else { | | 422 | } else { |
423 | tda16 = &sc->sc_tda16[nexttx]; | | 423 | tda16 = &sc->sc_tda16[nexttx]; |
424 | for (seg = 0; seg < dmamap->dm_nsegs; seg++) { | | 424 | for (seg = 0; seg < dmamap->dm_nsegs; seg++) { |
425 | tda16->tda_frags[seg].frag_ptr1 = | | 425 | tda16->tda_frags[seg].frag_ptr1 = |
426 | htosonic16(sc, | | 426 | htosonic16(sc, |
427 | (dmamap->dm_segs[seg].ds_addr >> 16) & | | 427 | (dmamap->dm_segs[seg].ds_addr >> 16) & |
428 | 0xffff); | | 428 | 0xffff); |
429 | tda16->tda_frags[seg].frag_ptr0 = | | 429 | tda16->tda_frags[seg].frag_ptr0 = |
430 | htosonic16(sc, | | 430 | htosonic16(sc, |
431 | dmamap->dm_segs[seg].ds_addr & 0xffff); | | 431 | dmamap->dm_segs[seg].ds_addr & 0xffff); |
432 | tda16->tda_frags[seg].frag_size = | | 432 | tda16->tda_frags[seg].frag_size = |
433 | htosonic16(sc, dmamap->dm_segs[seg].ds_len); | | 433 | htosonic16(sc, dmamap->dm_segs[seg].ds_len); |
434 | totlen += dmamap->dm_segs[seg].ds_len; | | 434 | totlen += dmamap->dm_segs[seg].ds_len; |
435 | } | | 435 | } |
436 | if (totlen < ETHER_PAD_LEN) { | | 436 | if (totlen < ETHER_PAD_LEN) { |
437 | tda16->tda_frags[seg].frag_ptr1 = | | 437 | tda16->tda_frags[seg].frag_ptr1 = |
438 | htosonic16(sc, | | 438 | htosonic16(sc, |
439 | (sc->sc_nulldma >> 16) & 0xffff); | | 439 | (sc->sc_nulldma >> 16) & 0xffff); |
440 | tda16->tda_frags[seg].frag_ptr0 = | | 440 | tda16->tda_frags[seg].frag_ptr0 = |
441 | htosonic16(sc, sc->sc_nulldma & 0xffff); | | 441 | htosonic16(sc, sc->sc_nulldma & 0xffff); |
442 | tda16->tda_frags[seg].frag_size = | | 442 | tda16->tda_frags[seg].frag_size = |
443 | htosonic16(sc, ETHER_PAD_LEN - totlen); | | 443 | htosonic16(sc, ETHER_PAD_LEN - totlen); |
444 | totlen = ETHER_PAD_LEN; | | 444 | totlen = ETHER_PAD_LEN; |
445 | seg++; | | 445 | seg++; |
446 | } | | 446 | } |
447 | | | 447 | |
448 | tda16->tda_status = 0; | | 448 | tda16->tda_status = 0; |
449 | tda16->tda_pktconfig = 0; | | 449 | tda16->tda_pktconfig = 0; |
450 | tda16->tda_pktsize = htosonic16(sc, totlen); | | 450 | tda16->tda_pktsize = htosonic16(sc, totlen); |
451 | tda16->tda_fragcnt = htosonic16(sc, seg); | | 451 | tda16->tda_fragcnt = htosonic16(sc, seg); |
452 | | | 452 | |
453 | /* Link it up. */ | | 453 | /* Link it up. */ |
454 | tda16->tda_frags[seg].frag_ptr0 = | | 454 | tda16->tda_frags[seg].frag_ptr0 = |
455 | htosonic16(sc, SONIC_CDTXADDR16(sc, | | 455 | htosonic16(sc, SONIC_CDTXADDR16(sc, |
456 | SONIC_NEXTTX(nexttx)) & 0xffff); | | 456 | SONIC_NEXTTX(nexttx)) & 0xffff); |
457 | | | 457 | |
458 | /* Sync the Tx descriptor. */ | | 458 | /* Sync the Tx descriptor. */ |
459 | SONIC_CDTXSYNC16(sc, nexttx, | | 459 | SONIC_CDTXSYNC16(sc, nexttx, |
460 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); | | 460 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); |
461 | } | | 461 | } |
462 | | | 462 | |
463 | /* Advance the Tx pointer. */ | | 463 | /* Advance the Tx pointer. */ |
464 | sc->sc_txpending++; | | 464 | sc->sc_txpending++; |
465 | sc->sc_txlast = nexttx; | | 465 | sc->sc_txlast = nexttx; |
466 | | | 466 | |
467 | /* | | 467 | /* |
468 | * Pass the packet to any BPF listeners. | | 468 | * Pass the packet to any BPF listeners. |
469 | */ | | 469 | */ |
470 | bpf_mtap(ifp, m0); | | 470 | bpf_mtap(ifp, m0); |
471 | } | | 471 | } |
472 | | | 472 | |
473 | if (sc->sc_txpending == (SONIC_NTXDESC - 1)) { | | 473 | if (sc->sc_txpending == (SONIC_NTXDESC - 1)) { |
474 | /* No more slots left; notify upper layer. */ | | 474 | /* No more slots left; notify upper layer. */ |
475 | ifp->if_flags |= IFF_OACTIVE; | | 475 | ifp->if_flags |= IFF_OACTIVE; |
476 | } | | 476 | } |
477 | | | 477 | |
478 | if (sc->sc_txpending != opending) { | | 478 | if (sc->sc_txpending != opending) { |
479 | /* | | 479 | /* |
480 | * We enqueued packets. If the transmitter was idle, | | 480 | * We enqueued packets. If the transmitter was idle, |
481 | * reset the txdirty pointer. | | 481 | * reset the txdirty pointer. |
482 | */ | | 482 | */ |
483 | if (opending == 0) | | 483 | if (opending == 0) |
484 | sc->sc_txdirty = SONIC_NEXTTX(olasttx); | | 484 | sc->sc_txdirty = SONIC_NEXTTX(olasttx); |
485 | | | 485 | |
486 | /* | | 486 | /* |
487 | * Stop the SONIC on the last packet we've set up, | | 487 | * Stop the SONIC on the last packet we've set up, |
488 | * and clear end-of-list on the descriptor previous | | 488 | * and clear end-of-list on the descriptor previous |
489 | * to our new chain. | | 489 | * to our new chain. |
490 | * | | 490 | * |
491 | * NOTE: our `seg' variable should still be valid! | | 491 | * NOTE: our `seg' variable should still be valid! |
492 | */ | | 492 | */ |
493 | if (sc->sc_32bit) { | | 493 | if (sc->sc_32bit) { |
494 | olseg = | | 494 | olseg = |
495 | sonic32toh(sc, sc->sc_tda32[olasttx].tda_fragcnt); | | 495 | sonic32toh(sc, sc->sc_tda32[olasttx].tda_fragcnt); |
496 | sc->sc_tda32[sc->sc_txlast].tda_frags[seg].frag_ptr0 |= | | 496 | sc->sc_tda32[sc->sc_txlast].tda_frags[seg].frag_ptr0 |= |
497 | htosonic32(sc, TDA_LINK_EOL); | | 497 | htosonic32(sc, TDA_LINK_EOL); |
498 | SONIC_CDTXSYNC32(sc, sc->sc_txlast, | | 498 | SONIC_CDTXSYNC32(sc, sc->sc_txlast, |
499 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); | | 499 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); |
500 | sc->sc_tda32[olasttx].tda_frags[olseg].frag_ptr0 &= | | 500 | sc->sc_tda32[olasttx].tda_frags[olseg].frag_ptr0 &= |
501 | htosonic32(sc, ~TDA_LINK_EOL); | | 501 | htosonic32(sc, ~TDA_LINK_EOL); |
502 | SONIC_CDTXSYNC32(sc, olasttx, | | 502 | SONIC_CDTXSYNC32(sc, olasttx, |
503 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); | | 503 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); |
504 | } else { | | 504 | } else { |
505 | olseg = | | 505 | olseg = |
506 | sonic16toh(sc, sc->sc_tda16[olasttx].tda_fragcnt); | | 506 | sonic16toh(sc, sc->sc_tda16[olasttx].tda_fragcnt); |
507 | sc->sc_tda16[sc->sc_txlast].tda_frags[seg].frag_ptr0 |= | | 507 | sc->sc_tda16[sc->sc_txlast].tda_frags[seg].frag_ptr0 |= |
508 | htosonic16(sc, TDA_LINK_EOL); | | 508 | htosonic16(sc, TDA_LINK_EOL); |
509 | SONIC_CDTXSYNC16(sc, sc->sc_txlast, | | 509 | SONIC_CDTXSYNC16(sc, sc->sc_txlast, |
510 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); | | 510 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); |
511 | sc->sc_tda16[olasttx].tda_frags[olseg].frag_ptr0 &= | | 511 | sc->sc_tda16[olasttx].tda_frags[olseg].frag_ptr0 &= |
512 | htosonic16(sc, ~TDA_LINK_EOL); | | 512 | htosonic16(sc, ~TDA_LINK_EOL); |
513 | SONIC_CDTXSYNC16(sc, olasttx, | | 513 | SONIC_CDTXSYNC16(sc, olasttx, |
514 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); | | 514 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); |
515 | } | | 515 | } |
516 | | | 516 | |
517 | /* Start the transmitter. */ | | 517 | /* Start the transmitter. */ |
518 | CSR_WRITE(sc, SONIC_CR, CR_TXP); | | 518 | CSR_WRITE(sc, SONIC_CR, CR_TXP); |
519 | | | 519 | |
520 | /* Set a watchdog timer in case the chip flakes out. */ | | 520 | /* Set a watchdog timer in case the chip flakes out. */ |
521 | ifp->if_timer = 5; | | 521 | ifp->if_timer = 5; |
522 | } | | 522 | } |
523 | } | | 523 | } |
524 | | | 524 | |
525 | /* | | 525 | /* |
526 | * sonic_watchdog: [ifnet interface function] | | 526 | * sonic_watchdog: [ifnet interface function] |
527 | * | | 527 | * |
528 | * Watchdog timer handler. | | 528 | * Watchdog timer handler. |
529 | */ | | 529 | */ |
530 | void | | 530 | void |
531 | sonic_watchdog(struct ifnet *ifp) | | 531 | sonic_watchdog(struct ifnet *ifp) |
532 | { | | 532 | { |
533 | struct sonic_softc *sc = ifp->if_softc; | | 533 | struct sonic_softc *sc = ifp->if_softc; |
534 | | | 534 | |
535 | printf("%s: device timeout\n", device_xname(sc->sc_dev)); | | 535 | printf("%s: device timeout\n", device_xname(sc->sc_dev)); |
536 | ifp->if_oerrors++; | | 536 | ifp->if_oerrors++; |
537 | | | 537 | |
538 | (void)sonic_init(ifp); | | 538 | (void)sonic_init(ifp); |
539 | } | | 539 | } |
540 | | | 540 | |
541 | /* | | 541 | /* |
542 | * sonic_ioctl: [ifnet interface function] | | 542 | * sonic_ioctl: [ifnet interface function] |
543 | * | | 543 | * |
544 | * Handle control requests from the operator. | | 544 | * Handle control requests from the operator. |
545 | */ | | 545 | */ |
546 | int | | 546 | int |
547 | sonic_ioctl(struct ifnet *ifp, u_long cmd, void *data) | | 547 | sonic_ioctl(struct ifnet *ifp, u_long cmd, void *data) |
548 | { | | 548 | { |
549 | int s, error; | | 549 | int s, error; |
550 | | | 550 | |
551 | s = splnet(); | | 551 | s = splnet(); |
552 | | | 552 | |
553 | error = ether_ioctl(ifp, cmd, data); | | 553 | error = ether_ioctl(ifp, cmd, data); |
554 | if (error == ENETRESET) { | | 554 | if (error == ENETRESET) { |
555 | /* | | 555 | /* |
556 | * Multicast list has changed; set the hardware | | 556 | * Multicast list has changed; set the hardware |
557 | * filter accordingly. | | 557 | * filter accordingly. |
558 | */ | | 558 | */ |
559 | if (ifp->if_flags & IFF_RUNNING) | | 559 | if (ifp->if_flags & IFF_RUNNING) |
560 | (void)sonic_init(ifp); | | 560 | (void)sonic_init(ifp); |
561 | error = 0; | | 561 | error = 0; |
562 | } | | 562 | } |
563 | | | 563 | |
564 | splx(s); | | 564 | splx(s); |
565 | return error; | | 565 | return error; |
566 | } | | 566 | } |
567 | | | 567 | |
568 | /* | | 568 | /* |
569 | * sonic_intr: | | 569 | * sonic_intr: |
570 | * | | 570 | * |
571 | * Interrupt service routine. | | 571 | * Interrupt service routine. |
572 | */ | | 572 | */ |
573 | int | | 573 | int |
574 | sonic_intr(void *arg) | | 574 | sonic_intr(void *arg) |
575 | { | | 575 | { |
576 | struct sonic_softc *sc = arg; | | 576 | struct sonic_softc *sc = arg; |
577 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | | 577 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
578 | uint16_t isr; | | 578 | uint16_t isr; |
579 | int handled = 0, wantinit; | | 579 | int handled = 0, wantinit; |
580 | | | 580 | |
581 | for (wantinit = 0; wantinit == 0;) { | | 581 | for (wantinit = 0; wantinit == 0;) { |
582 | isr = CSR_READ(sc, SONIC_ISR) & sc->sc_imr; | | 582 | isr = CSR_READ(sc, SONIC_ISR) & sc->sc_imr; |
583 | if (isr == 0) | | 583 | if (isr == 0) |
584 | break; | | 584 | break; |
585 | CSR_WRITE(sc, SONIC_ISR, isr); /* ACK */ | | 585 | CSR_WRITE(sc, SONIC_ISR, isr); /* ACK */ |
586 | | | 586 | |
587 | handled = 1; | | 587 | handled = 1; |
588 | | | 588 | |
589 | if (isr & IMR_PRX) | | 589 | if (isr & IMR_PRX) |
590 | sonic_rxintr(sc); | | 590 | sonic_rxintr(sc); |
591 | | | 591 | |
592 | if (isr & (IMR_PTX|IMR_TXER)) { | | 592 | if (isr & (IMR_PTX|IMR_TXER)) { |
593 | if (sonic_txintr(sc) & TCR_FU) { | | 593 | if (sonic_txintr(sc) & TCR_FU) { |
594 | printf("%s: transmit FIFO underrun\n", | | 594 | printf("%s: transmit FIFO underrun\n", |
595 | device_xname(sc->sc_dev)); | | 595 | device_xname(sc->sc_dev)); |
596 | wantinit = 1; | | 596 | wantinit = 1; |
597 | } | | 597 | } |
598 | } | | 598 | } |
599 | | | 599 | |
600 | if (isr & (IMR_RFO|IMR_RBA|IMR_RBE|IMR_RDE)) { | | 600 | if (isr & (IMR_RFO|IMR_RBA|IMR_RBE|IMR_RDE)) { |
601 | #define PRINTERR(bit, str) \ | | 601 | #define PRINTERR(bit, str) \ |
602 | if (isr & (bit)) \ | | 602 | if (isr & (bit)) \ |
603 | printf("%s: %s\n",device_xname(sc->sc_dev), str) | | 603 | printf("%s: %s\n",device_xname(sc->sc_dev), str) |
604 | PRINTERR(IMR_RFO, "receive FIFO overrun"); | | 604 | PRINTERR(IMR_RFO, "receive FIFO overrun"); |
605 | PRINTERR(IMR_RBA, "receive buffer exceeded"); | | 605 | PRINTERR(IMR_RBA, "receive buffer exceeded"); |
606 | PRINTERR(IMR_RBE, "receive buffers exhausted"); | | 606 | PRINTERR(IMR_RBE, "receive buffers exhausted"); |
607 | PRINTERR(IMR_RDE, "receive descriptors exhausted"); | | 607 | PRINTERR(IMR_RDE, "receive descriptors exhausted"); |
608 | wantinit = 1; | | 608 | wantinit = 1; |
609 | } | | 609 | } |
610 | } | | 610 | } |
611 | | | 611 | |
612 | if (handled) { | | 612 | if (handled) { |
613 | if (wantinit) | | 613 | if (wantinit) |
614 | (void)sonic_init(ifp); | | 614 | (void)sonic_init(ifp); |
615 | sonic_start(ifp); | | 615 | sonic_start(ifp); |
616 | } | | 616 | } |
617 | | | 617 | |
618 | return handled; | | 618 | return handled; |
619 | } | | 619 | } |
620 | | | 620 | |
621 | /* | | 621 | /* |
622 | * sonic_txintr: | | 622 | * sonic_txintr: |
623 | * | | 623 | * |
624 | * Helper; handle transmit complete interrupts. | | 624 | * Helper; handle transmit complete interrupts. |
625 | */ | | 625 | */ |
626 | uint16_t | | 626 | uint16_t |
627 | sonic_txintr(struct sonic_softc *sc) | | 627 | sonic_txintr(struct sonic_softc *sc) |
628 | { | | 628 | { |
629 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | | 629 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
630 | struct sonic_descsoft *ds; | | 630 | struct sonic_descsoft *ds; |
631 | struct sonic_tda32 *tda32; | | 631 | struct sonic_tda32 *tda32; |
632 | struct sonic_tda16 *tda16; | | 632 | struct sonic_tda16 *tda16; |
633 | uint16_t status, totstat = 0; | | 633 | uint16_t status, totstat = 0; |
634 | int i; | | 634 | int i; |
635 | | | 635 | |
636 | ifp->if_flags &= ~IFF_OACTIVE; | | 636 | ifp->if_flags &= ~IFF_OACTIVE; |
637 | | | 637 | |
638 | for (i = sc->sc_txdirty; sc->sc_txpending != 0; | | 638 | for (i = sc->sc_txdirty; sc->sc_txpending != 0; |
639 | i = SONIC_NEXTTX(i), sc->sc_txpending--) { | | 639 | i = SONIC_NEXTTX(i), sc->sc_txpending--) { |
640 | ds = &sc->sc_txsoft[i]; | | 640 | ds = &sc->sc_txsoft[i]; |
641 | | | 641 | |
642 | if (sc->sc_32bit) { | | 642 | if (sc->sc_32bit) { |
643 | SONIC_CDTXSYNC32(sc, i, | | 643 | SONIC_CDTXSYNC32(sc, i, |
644 | BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); | | 644 | BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); |
645 | tda32 = &sc->sc_tda32[i]; | | 645 | tda32 = &sc->sc_tda32[i]; |
646 | status = sonic32toh(sc, tda32->tda_status); | | 646 | status = sonic32toh(sc, tda32->tda_status); |
647 | SONIC_CDTXSYNC32(sc, i, BUS_DMASYNC_PREREAD); | | 647 | SONIC_CDTXSYNC32(sc, i, BUS_DMASYNC_PREREAD); |
648 | } else { | | 648 | } else { |
649 | SONIC_CDTXSYNC16(sc, i, | | 649 | SONIC_CDTXSYNC16(sc, i, |
650 | BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); | | 650 | BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); |
651 | tda16 = &sc->sc_tda16[i]; | | 651 | tda16 = &sc->sc_tda16[i]; |
652 | status = sonic16toh(sc, tda16->tda_status); | | 652 | status = sonic16toh(sc, tda16->tda_status); |
653 | SONIC_CDTXSYNC16(sc, i, BUS_DMASYNC_PREREAD); | | 653 | SONIC_CDTXSYNC16(sc, i, BUS_DMASYNC_PREREAD); |
654 | } | | 654 | } |
655 | | | 655 | |
656 | if ((status & ~(TCR_EXDIS|TCR_CRCI|TCR_POWC|TCR_PINT)) == 0) | | 656 | if ((status & ~(TCR_EXDIS|TCR_CRCI|TCR_POWC|TCR_PINT)) == 0) |
657 | break; | | 657 | break; |
658 | | | 658 | |
659 | totstat |= status; | | 659 | totstat |= status; |
660 | | | 660 | |
661 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, | | 661 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, |
662 | ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE); | | 662 | ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE); |
663 | bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap); | | 663 | bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap); |
664 | m_freem(ds->ds_mbuf); | | 664 | m_freem(ds->ds_mbuf); |
665 | ds->ds_mbuf = NULL; | | 665 | ds->ds_mbuf = NULL; |
666 | | | 666 | |
667 | /* | | 667 | /* |
668 | * Check for errors and collisions. | | 668 | * Check for errors and collisions. |
669 | */ | | 669 | */ |
670 | if (status & TCR_PTX) | | 670 | if (status & TCR_PTX) |
671 | ifp->if_opackets++; | | 671 | ifp->if_opackets++; |
672 | else | | 672 | else |
673 | ifp->if_oerrors++; | | 673 | ifp->if_oerrors++; |
674 | ifp->if_collisions += TDA_STATUS_NCOL(status); | | 674 | ifp->if_collisions += TDA_STATUS_NCOL(status); |
675 | } | | 675 | } |
676 | | | 676 | |
677 | /* Update the dirty transmit buffer pointer. */ | | 677 | /* Update the dirty transmit buffer pointer. */ |
678 | sc->sc_txdirty = i; | | 678 | sc->sc_txdirty = i; |
679 | | | 679 | |
680 | /* | | 680 | /* |
681 | * Cancel the watchdog timer if there are no pending | | 681 | * Cancel the watchdog timer if there are no pending |
682 | * transmissions. | | 682 | * transmissions. |
683 | */ | | 683 | */ |
684 | if (sc->sc_txpending == 0) | | 684 | if (sc->sc_txpending == 0) |
685 | ifp->if_timer = 0; | | 685 | ifp->if_timer = 0; |
686 | | | 686 | |
687 | return totstat; | | 687 | return totstat; |
688 | } | | 688 | } |
689 | | | 689 | |
690 | /* | | 690 | /* |
691 | * sonic_rxintr: | | 691 | * sonic_rxintr: |
692 | * | | 692 | * |
693 | * Helper; handle receive interrupts. | | 693 | * Helper; handle receive interrupts. |
694 | */ | | 694 | */ |
695 | void | | 695 | void |
696 | sonic_rxintr(struct sonic_softc *sc) | | 696 | sonic_rxintr(struct sonic_softc *sc) |
697 | { | | 697 | { |
698 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | | 698 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
699 | struct sonic_descsoft *ds; | | 699 | struct sonic_descsoft *ds; |
700 | struct sonic_rda32 *rda32; | | 700 | struct sonic_rda32 *rda32; |
701 | struct sonic_rda16 *rda16; | | 701 | struct sonic_rda16 *rda16; |
702 | struct mbuf *m; | | 702 | struct mbuf *m; |
703 | int i, len; | | 703 | int i, len; |
704 | uint16_t status, bytecount, ptr0, ptr1, seqno; | | 704 | uint16_t status, bytecount, ptr0, ptr1, seqno; |
705 | | | 705 | |
706 | for (i = sc->sc_rxptr;; i = SONIC_NEXTRX(i)) { | | 706 | for (i = sc->sc_rxptr;; i = SONIC_NEXTRX(i)) { |
707 | ds = &sc->sc_rxsoft[i]; | | 707 | ds = &sc->sc_rxsoft[i]; |
708 | | | 708 | |
709 | if (sc->sc_32bit) { | | 709 | if (sc->sc_32bit) { |
710 | SONIC_CDRXSYNC32(sc, i, | | 710 | SONIC_CDRXSYNC32(sc, i, |
711 | BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); | | 711 | BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); |
712 | rda32 = &sc->sc_rda32[i]; | | 712 | rda32 = &sc->sc_rda32[i]; |
713 | SONIC_CDRXSYNC32(sc, i, BUS_DMASYNC_PREREAD); | | 713 | SONIC_CDRXSYNC32(sc, i, BUS_DMASYNC_PREREAD); |
714 | if (rda32->rda_inuse != 0) | | 714 | if (rda32->rda_inuse != 0) |
715 | break; | | 715 | break; |
716 | status = sonic32toh(sc, rda32->rda_status); | | 716 | status = sonic32toh(sc, rda32->rda_status); |
717 | bytecount = sonic32toh(sc, rda32->rda_bytecount); | | 717 | bytecount = sonic32toh(sc, rda32->rda_bytecount); |
718 | ptr0 = sonic32toh(sc, rda32->rda_pkt_ptr0); | | 718 | ptr0 = sonic32toh(sc, rda32->rda_pkt_ptr0); |
719 | ptr1 = sonic32toh(sc, rda32->rda_pkt_ptr1); | | 719 | ptr1 = sonic32toh(sc, rda32->rda_pkt_ptr1); |
720 | seqno = sonic32toh(sc, rda32->rda_seqno); | | 720 | seqno = sonic32toh(sc, rda32->rda_seqno); |
721 | } else { | | 721 | } else { |
722 | SONIC_CDRXSYNC16(sc, i, | | 722 | SONIC_CDRXSYNC16(sc, i, |
723 | BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); | | 723 | BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); |
724 | rda16 = &sc->sc_rda16[i]; | | 724 | rda16 = &sc->sc_rda16[i]; |
725 | SONIC_CDRXSYNC16(sc, i, BUS_DMASYNC_PREREAD); | | 725 | SONIC_CDRXSYNC16(sc, i, BUS_DMASYNC_PREREAD); |
726 | if (rda16->rda_inuse != 0) | | 726 | if (rda16->rda_inuse != 0) |
727 | break; | | 727 | break; |
728 | status = sonic16toh(sc, rda16->rda_status); | | 728 | status = sonic16toh(sc, rda16->rda_status); |
729 | bytecount = sonic16toh(sc, rda16->rda_bytecount); | | 729 | bytecount = sonic16toh(sc, rda16->rda_bytecount); |
730 | ptr0 = sonic16toh(sc, rda16->rda_pkt_ptr0); | | 730 | ptr0 = sonic16toh(sc, rda16->rda_pkt_ptr0); |
731 | ptr1 = sonic16toh(sc, rda16->rda_pkt_ptr1); | | 731 | ptr1 = sonic16toh(sc, rda16->rda_pkt_ptr1); |
732 | seqno = sonic16toh(sc, rda16->rda_seqno); | | 732 | seqno = sonic16toh(sc, rda16->rda_seqno); |
733 | } | | 733 | } |
734 | | | 734 | |
735 | /* | | 735 | /* |
736 | * Make absolutely sure this is the only packet | | 736 | * Make absolutely sure this is the only packet |
737 | * in this receive buffer. Our entire Rx buffer | | 737 | * in this receive buffer. Our entire Rx buffer |
738 | * management scheme depends on this, and if the | | 738 | * management scheme depends on this, and if the |
739 | * SONIC didn't follow our rule, it means we've | | 739 | * SONIC didn't follow our rule, it means we've |
740 | * misconfigured it. | | 740 | * misconfigured it. |
741 | */ | | 741 | */ |
742 | KASSERT(status & RCR_LPKT); | | 742 | KASSERT(status & RCR_LPKT); |
743 | | | 743 | |
744 | /* | | 744 | /* |
745 | * Make sure the packet arrived OK. If an error occurred, | | 745 | * Make sure the packet arrived OK. If an error occurred, |
746 | * update stats and reset the descriptor. The buffer will | | 746 | * update stats and reset the descriptor. The buffer will |
747 | * be reused the next time the descriptor comes up in the | | 747 | * be reused the next time the descriptor comes up in the |
748 | * ring. | | 748 | * ring. |
749 | */ | | 749 | */ |
750 | if ((status & RCR_PRX) == 0) { | | 750 | if ((status & RCR_PRX) == 0) { |
751 | if (status & RCR_FAER) | | 751 | if (status & RCR_FAER) |
752 | printf("%s: Rx frame alignment error\n", | | 752 | printf("%s: Rx frame alignment error\n", |
753 | device_xname(sc->sc_dev)); | | 753 | device_xname(sc->sc_dev)); |
754 | else if (status & RCR_CRCR) | | 754 | else if (status & RCR_CRCR) |
755 | printf("%s: Rx CRC error\n", | | 755 | printf("%s: Rx CRC error\n", |
756 | device_xname(sc->sc_dev)); | | 756 | device_xname(sc->sc_dev)); |
757 | ifp->if_ierrors++; | | 757 | ifp->if_ierrors++; |
758 | SONIC_INIT_RXDESC(sc, i); | | 758 | SONIC_INIT_RXDESC(sc, i); |
759 | continue; | | 759 | continue; |
760 | } | | 760 | } |
761 | | | 761 | |
762 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, | | 762 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, |
763 | ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD); | | 763 | ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD); |
764 | | | 764 | |
765 | /* | | 765 | /* |
766 | * The SONIC includes the CRC with every packet. | | 766 | * The SONIC includes the CRC with every packet. |
767 | */ | | 767 | */ |
768 | len = bytecount - ETHER_CRC_LEN; | | 768 | len = bytecount - ETHER_CRC_LEN; |
769 | | | 769 | |
770 | /* | | 770 | /* |
771 | * Ok, if the chip is in 32-bit mode, then receive | | 771 | * Ok, if the chip is in 32-bit mode, then receive |
772 | * buffers must be aligned to 32-bit boundaries, | | 772 | * buffers must be aligned to 32-bit boundaries, |
773 | * which means the payload is misaligned. In this | | 773 | * which means the payload is misaligned. In this |
774 | * case, we must allocate a new mbuf, and copy the | | 774 | * case, we must allocate a new mbuf, and copy the |
775 | * packet into it, scooted forward 2 bytes to ensure | | 775 | * packet into it, scooted forward 2 bytes to ensure |
776 | * proper alignment. | | 776 | * proper alignment. |
777 | * | | 777 | * |
778 | * Note, in 16-bit mode, we can configure the SONIC | | 778 | * Note, in 16-bit mode, we can configure the SONIC |
779 | * to do what we want, and we have. | | 779 | * to do what we want, and we have. |
780 | */ | | 780 | */ |
781 | #ifndef __NO_STRICT_ALIGNMENT | | 781 | #ifndef __NO_STRICT_ALIGNMENT |
782 | if (sc->sc_32bit) { | | 782 | if (sc->sc_32bit) { |
783 | MGETHDR(m, M_DONTWAIT, MT_DATA); | | 783 | MGETHDR(m, M_DONTWAIT, MT_DATA); |
784 | if (m == NULL) | | 784 | if (m == NULL) |
785 | goto dropit; | | 785 | goto dropit; |
786 | if (len > (MHLEN - 2)) { | | 786 | if (len > (MHLEN - 2)) { |
787 | MCLGET(m, M_DONTWAIT); | | 787 | MCLGET(m, M_DONTWAIT); |
788 | if ((m->m_flags & M_EXT) == 0) | | 788 | if ((m->m_flags & M_EXT) == 0) { |
| | | 789 | m_freem(m); |
789 | goto dropit; | | 790 | goto dropit; |
| | | 791 | } |
790 | } | | 792 | } |
791 | m->m_data += 2; | | 793 | m->m_data += 2; |
792 | /* | | 794 | /* |
793 | * Note that we use a cluster for incoming frames, | | 795 | * Note that we use a cluster for incoming frames, |
794 | * so the buffer is virtually contiguous. | | 796 | * so the buffer is virtually contiguous. |
795 | */ | | 797 | */ |
796 | memcpy(mtod(m, void *), mtod(ds->ds_mbuf, void *), | | 798 | memcpy(mtod(m, void *), mtod(ds->ds_mbuf, void *), |
797 | len); | | 799 | len); |
798 | SONIC_INIT_RXDESC(sc, i); | | 800 | SONIC_INIT_RXDESC(sc, i); |
799 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, | | 801 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, |
800 | ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); | | 802 | ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); |
801 | } else | | 803 | } else |
802 | #endif /* ! __NO_STRICT_ALIGNMENT */ | | 804 | #endif /* ! __NO_STRICT_ALIGNMENT */ |
803 | /* | | 805 | /* |
804 | * If the packet is small enough to fit in a single | | 806 | * If the packet is small enough to fit in a single |
805 | * header mbuf, allocate one and copy the data into | | 807 | * header mbuf, allocate one and copy the data into |
806 | * it. This greatly reduces memory consumption when | | 808 | * it. This greatly reduces memory consumption when |
807 | * we receive lots of small packets. | | 809 | * we receive lots of small packets. |
808 | */ | | 810 | */ |
809 | if (sonic_copy_small != 0 && len <= (MHLEN - 2)) { | | 811 | if (sonic_copy_small != 0 && len <= (MHLEN - 2)) { |
810 | MGETHDR(m, M_DONTWAIT, MT_DATA); | | 812 | MGETHDR(m, M_DONTWAIT, MT_DATA); |
811 | if (m == NULL) | | 813 | if (m == NULL) |
812 | goto dropit; | | 814 | goto dropit; |
813 | m->m_data += 2; | | 815 | m->m_data += 2; |
814 | /* | | 816 | /* |
815 | * Note that we use a cluster for incoming frames, | | 817 | * Note that we use a cluster for incoming frames, |
816 | * so the buffer is virtually contiguous. | | 818 | * so the buffer is virtually contiguous. |
817 | */ | | 819 | */ |
818 | memcpy(mtod(m, void *), mtod(ds->ds_mbuf, void *), | | 820 | memcpy(mtod(m, void *), mtod(ds->ds_mbuf, void *), |
819 | len); | | 821 | len); |
820 | SONIC_INIT_RXDESC(sc, i); | | 822 | SONIC_INIT_RXDESC(sc, i); |
821 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, | | 823 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, |
822 | ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); | | 824 | ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); |
823 | } else { | | 825 | } else { |
824 | m = ds->ds_mbuf; | | 826 | m = ds->ds_mbuf; |
825 | if (sonic_add_rxbuf(sc, i) != 0) { | | 827 | if (sonic_add_rxbuf(sc, i) != 0) { |
826 | dropit: | | 828 | dropit: |
827 | ifp->if_ierrors++; | | 829 | ifp->if_ierrors++; |
828 | SONIC_INIT_RXDESC(sc, i); | | 830 | SONIC_INIT_RXDESC(sc, i); |
829 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, | | 831 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, |
830 | ds->ds_dmamap->dm_mapsize, | | 832 | ds->ds_dmamap->dm_mapsize, |
831 | BUS_DMASYNC_PREREAD); | | 833 | BUS_DMASYNC_PREREAD); |
832 | continue; | | 834 | continue; |
833 | } | | 835 | } |
834 | } | | 836 | } |
835 | | | 837 | |
836 | ifp->if_ipackets++; | | 838 | ifp->if_ipackets++; |
837 | m->m_pkthdr.rcvif = ifp; | | 839 | m->m_pkthdr.rcvif = ifp; |
838 | m->m_pkthdr.len = m->m_len = len; | | 840 | m->m_pkthdr.len = m->m_len = len; |
839 | | | 841 | |
840 | /* | | 842 | /* |
841 | * Pass this up to any BPF listeners. | | 843 | * Pass this up to any BPF listeners. |
842 | */ | | 844 | */ |
843 | bpf_mtap(ifp, m); | | 845 | bpf_mtap(ifp, m); |
844 | | | 846 | |
845 | /* Pass it on. */ | | 847 | /* Pass it on. */ |
846 | (*ifp->if_input)(ifp, m); | | 848 | (*ifp->if_input)(ifp, m); |
847 | } | | 849 | } |
848 | | | 850 | |
849 | /* Update the receive pointer. */ | | 851 | /* Update the receive pointer. */ |
850 | sc->sc_rxptr = i; | | 852 | sc->sc_rxptr = i; |
851 | CSR_WRITE(sc, SONIC_RWR, SONIC_CDRRADDR(sc, SONIC_PREVRX(i))); | | 853 | CSR_WRITE(sc, SONIC_RWR, SONIC_CDRRADDR(sc, SONIC_PREVRX(i))); |
852 | } | | 854 | } |
853 | | | 855 | |
854 | /* | | 856 | /* |
855 | * sonic_reset: | | 857 | * sonic_reset: |
856 | * | | 858 | * |
857 | * Perform a soft reset on the SONIC. | | 859 | * Perform a soft reset on the SONIC. |
858 | */ | | 860 | */ |
859 | void | | 861 | void |
860 | sonic_reset(struct sonic_softc *sc) | | 862 | sonic_reset(struct sonic_softc *sc) |
861 | { | | 863 | { |
862 | | | 864 | |
863 | /* stop TX, RX and timer, and ensure RST is clear */ | | 865 | /* stop TX, RX and timer, and ensure RST is clear */ |
864 | CSR_WRITE(sc, SONIC_CR, CR_STP | CR_RXDIS | CR_HTX); | | 866 | CSR_WRITE(sc, SONIC_CR, CR_STP | CR_RXDIS | CR_HTX); |
865 | delay(1000); | | 867 | delay(1000); |
866 | | | 868 | |
867 | CSR_WRITE(sc, SONIC_CR, CR_RST); | | 869 | CSR_WRITE(sc, SONIC_CR, CR_RST); |
868 | delay(1000); | | 870 | delay(1000); |
869 | | | 871 | |
870 | /* clear all interrupts */ | | 872 | /* clear all interrupts */ |
871 | CSR_WRITE(sc, SONIC_IMR, 0); | | 873 | CSR_WRITE(sc, SONIC_IMR, 0); |
872 | CSR_WRITE(sc, SONIC_ISR, IMR_ALL); | | 874 | CSR_WRITE(sc, SONIC_ISR, IMR_ALL); |
873 | | | 875 | |
874 | CSR_WRITE(sc, SONIC_CR, 0); | | 876 | CSR_WRITE(sc, SONIC_CR, 0); |
875 | delay(1000); | | 877 | delay(1000); |
876 | } | | 878 | } |
877 | | | 879 | |
878 | /* | | 880 | /* |
879 | * sonic_init: [ifnet interface function] | | 881 | * sonic_init: [ifnet interface function] |
880 | * | | 882 | * |
881 | * Initialize the interface. Must be called at splnet(). | | 883 | * Initialize the interface. Must be called at splnet(). |
882 | */ | | 884 | */ |
883 | int | | 885 | int |
884 | sonic_init(struct ifnet *ifp) | | 886 | sonic_init(struct ifnet *ifp) |
885 | { | | 887 | { |
886 | struct sonic_softc *sc = ifp->if_softc; | | 888 | struct sonic_softc *sc = ifp->if_softc; |
887 | struct sonic_descsoft *ds; | | 889 | struct sonic_descsoft *ds; |
888 | int i, error = 0; | | 890 | int i, error = 0; |
889 | uint16_t reg; | | 891 | uint16_t reg; |
890 | | | 892 | |
891 | /* | | 893 | /* |
892 | * Cancel any pending I/O. | | 894 | * Cancel any pending I/O. |
893 | */ | | 895 | */ |
894 | sonic_stop(ifp, 0); | | 896 | sonic_stop(ifp, 0); |
895 | | | 897 | |
896 | /* | | 898 | /* |
897 | * Reset the SONIC to a known state. | | 899 | * Reset the SONIC to a known state. |
898 | */ | | 900 | */ |
899 | sonic_reset(sc); | | 901 | sonic_reset(sc); |
900 | | | 902 | |
901 | /* | | 903 | /* |
902 | * Bring the SONIC into reset state, and program the DCR. | | 904 | * Bring the SONIC into reset state, and program the DCR. |
903 | * | | 905 | * |
904 | * Note: We don't bother optimizing the transmit and receive | | 906 | * Note: We don't bother optimizing the transmit and receive |
905 | * thresholds, here. TFT/RFT values should be set in MD attachments. | | 907 | * thresholds, here. TFT/RFT values should be set in MD attachments. |
906 | */ | | 908 | */ |
907 | reg = sc->sc_dcr; | | 909 | reg = sc->sc_dcr; |
908 | if (sc->sc_32bit) | | 910 | if (sc->sc_32bit) |
909 | reg |= DCR_DW; | | 911 | reg |= DCR_DW; |
910 | CSR_WRITE(sc, SONIC_CR, CR_RST); | | 912 | CSR_WRITE(sc, SONIC_CR, CR_RST); |
911 | CSR_WRITE(sc, SONIC_DCR, reg); | | 913 | CSR_WRITE(sc, SONIC_DCR, reg); |
912 | CSR_WRITE(sc, SONIC_DCR2, sc->sc_dcr2); | | 914 | CSR_WRITE(sc, SONIC_DCR2, sc->sc_dcr2); |
913 | CSR_WRITE(sc, SONIC_CR, 0); | | 915 | CSR_WRITE(sc, SONIC_CR, 0); |
914 | | | 916 | |
915 | /* | | 917 | /* |
916 | * Initialize the transmit descriptors. | | 918 | * Initialize the transmit descriptors. |
917 | */ | | 919 | */ |
918 | if (sc->sc_32bit) { | | 920 | if (sc->sc_32bit) { |
919 | for (i = 0; i < SONIC_NTXDESC; i++) { | | 921 | for (i = 0; i < SONIC_NTXDESC; i++) { |
920 | memset(&sc->sc_tda32[i], 0, sizeof(struct sonic_tda32)); | | 922 | memset(&sc->sc_tda32[i], 0, sizeof(struct sonic_tda32)); |
921 | SONIC_CDTXSYNC32(sc, i, | | 923 | SONIC_CDTXSYNC32(sc, i, |
922 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); | | 924 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); |
923 | } | | 925 | } |
924 | } else { | | 926 | } else { |
925 | for (i = 0; i < SONIC_NTXDESC; i++) { | | 927 | for (i = 0; i < SONIC_NTXDESC; i++) { |
926 | memset(&sc->sc_tda16[i], 0, sizeof(struct sonic_tda16)); | | 928 | memset(&sc->sc_tda16[i], 0, sizeof(struct sonic_tda16)); |
927 | SONIC_CDTXSYNC16(sc, i, | | 929 | SONIC_CDTXSYNC16(sc, i, |
928 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); | | 930 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); |
929 | } | | 931 | } |
930 | } | | 932 | } |
931 | sc->sc_txpending = 0; | | 933 | sc->sc_txpending = 0; |
932 | sc->sc_txdirty = 0; | | 934 | sc->sc_txdirty = 0; |
933 | sc->sc_txlast = SONIC_NTXDESC - 1; | | 935 | sc->sc_txlast = SONIC_NTXDESC - 1; |
934 | | | 936 | |
935 | /* | | 937 | /* |
936 | * Initialize the receive descriptor ring. | | 938 | * Initialize the receive descriptor ring. |
937 | */ | | 939 | */ |
938 | for (i = 0; i < SONIC_NRXDESC; i++) { | | 940 | for (i = 0; i < SONIC_NRXDESC; i++) { |
939 | ds = &sc->sc_rxsoft[i]; | | 941 | ds = &sc->sc_rxsoft[i]; |
940 | if (ds->ds_mbuf == NULL) { | | 942 | if (ds->ds_mbuf == NULL) { |
941 | if ((error = sonic_add_rxbuf(sc, i)) != 0) { | | 943 | if ((error = sonic_add_rxbuf(sc, i)) != 0) { |
942 | printf("%s: unable to allocate or map Rx " | | 944 | printf("%s: unable to allocate or map Rx " |
943 | "buffer %d, error = %d\n", | | 945 | "buffer %d, error = %d\n", |
944 | device_xname(sc->sc_dev), i, error); | | 946 | device_xname(sc->sc_dev), i, error); |
945 | /* | | 947 | /* |
946 | * XXX Should attempt to run with fewer receive | | 948 | * XXX Should attempt to run with fewer receive |
947 | * XXX buffers instead of just failing. | | 949 | * XXX buffers instead of just failing. |
948 | */ | | 950 | */ |
949 | sonic_rxdrain(sc); | | 951 | sonic_rxdrain(sc); |
950 | goto out; | | 952 | goto out; |
951 | } | | 953 | } |
952 | } else | | 954 | } else |
953 | SONIC_INIT_RXDESC(sc, i); | | 955 | SONIC_INIT_RXDESC(sc, i); |
954 | } | | 956 | } |
955 | sc->sc_rxptr = 0; | | 957 | sc->sc_rxptr = 0; |
956 | | | 958 | |
957 | /* Give the transmit ring to the SONIC. */ | | 959 | /* Give the transmit ring to the SONIC. */ |
958 | CSR_WRITE(sc, SONIC_UTDAR, (SONIC_CDTXADDR(sc, 0) >> 16) & 0xffff); | | 960 | CSR_WRITE(sc, SONIC_UTDAR, (SONIC_CDTXADDR(sc, 0) >> 16) & 0xffff); |
959 | CSR_WRITE(sc, SONIC_CTDAR, SONIC_CDTXADDR(sc, 0) & 0xffff); | | 961 | CSR_WRITE(sc, SONIC_CTDAR, SONIC_CDTXADDR(sc, 0) & 0xffff); |
960 | | | 962 | |
961 | /* Give the receive descriptor ring to the SONIC. */ | | 963 | /* Give the receive descriptor ring to the SONIC. */ |
962 | CSR_WRITE(sc, SONIC_URDAR, (SONIC_CDRXADDR(sc, 0) >> 16) & 0xffff); | | 964 | CSR_WRITE(sc, SONIC_URDAR, (SONIC_CDRXADDR(sc, 0) >> 16) & 0xffff); |
963 | CSR_WRITE(sc, SONIC_CRDAR, SONIC_CDRXADDR(sc, 0) & 0xffff); | | 965 | CSR_WRITE(sc, SONIC_CRDAR, SONIC_CDRXADDR(sc, 0) & 0xffff); |
964 | | | 966 | |
965 | /* Give the receive buffer ring to the SONIC. */ | | 967 | /* Give the receive buffer ring to the SONIC. */ |
966 | CSR_WRITE(sc, SONIC_URRAR, (SONIC_CDRRADDR(sc, 0) >> 16) & 0xffff); | | 968 | CSR_WRITE(sc, SONIC_URRAR, (SONIC_CDRRADDR(sc, 0) >> 16) & 0xffff); |
967 | CSR_WRITE(sc, SONIC_RSAR, SONIC_CDRRADDR(sc, 0) & 0xffff); | | 969 | CSR_WRITE(sc, SONIC_RSAR, SONIC_CDRRADDR(sc, 0) & 0xffff); |
968 | if (sc->sc_32bit) | | 970 | if (sc->sc_32bit) |
969 | CSR_WRITE(sc, SONIC_REAR, | | 971 | CSR_WRITE(sc, SONIC_REAR, |
970 | (SONIC_CDRRADDR(sc, SONIC_NRXDESC - 1) + | | 972 | (SONIC_CDRRADDR(sc, SONIC_NRXDESC - 1) + |
971 | sizeof(struct sonic_rra32)) & 0xffff); | | 973 | sizeof(struct sonic_rra32)) & 0xffff); |
972 | else | | 974 | else |
973 | CSR_WRITE(sc, SONIC_REAR, | | 975 | CSR_WRITE(sc, SONIC_REAR, |
974 | (SONIC_CDRRADDR(sc, SONIC_NRXDESC - 1) + | | 976 | (SONIC_CDRRADDR(sc, SONIC_NRXDESC - 1) + |
975 | sizeof(struct sonic_rra16)) & 0xffff); | | 977 | sizeof(struct sonic_rra16)) & 0xffff); |
976 | CSR_WRITE(sc, SONIC_RRR, SONIC_CDRRADDR(sc, 0) & 0xffff); | | 978 | CSR_WRITE(sc, SONIC_RRR, SONIC_CDRRADDR(sc, 0) & 0xffff); |
977 | CSR_WRITE(sc, SONIC_RWR, SONIC_CDRRADDR(sc, SONIC_NRXDESC - 1)); | | 979 | CSR_WRITE(sc, SONIC_RWR, SONIC_CDRRADDR(sc, SONIC_NRXDESC - 1)); |
978 | | | 980 | |
979 | /* | | 981 | /* |
980 | * Set the End-Of-Buffer counter such that only one packet | | 982 | * Set the End-Of-Buffer counter such that only one packet |
981 | * will be placed into each buffer we provide. Note we are | | 983 | * will be placed into each buffer we provide. Note we are |
982 | * following the recommendation of section 3.4.4 of the manual | | 984 | * following the recommendation of section 3.4.4 of the manual |
983 | * here, and have "lengthened" the receive buffers accordingly. | | 985 | * here, and have "lengthened" the receive buffers accordingly. |
984 | */ | | 986 | */ |
985 | if (sc->sc_32bit) | | 987 | if (sc->sc_32bit) |
986 | CSR_WRITE(sc, SONIC_EOBC, (ETHER_MAX_LEN + 2) / 2); | | 988 | CSR_WRITE(sc, SONIC_EOBC, (ETHER_MAX_LEN + 2) / 2); |
987 | else | | 989 | else |
988 | CSR_WRITE(sc, SONIC_EOBC, (ETHER_MAX_LEN / 2)); | | 990 | CSR_WRITE(sc, SONIC_EOBC, (ETHER_MAX_LEN / 2)); |
989 | | | 991 | |
990 | /* Reset the receive sequence counter. */ | | 992 | /* Reset the receive sequence counter. */ |
991 | CSR_WRITE(sc, SONIC_RSC, 0); | | 993 | CSR_WRITE(sc, SONIC_RSC, 0); |
992 | | | 994 | |
993 | /* Clear the tally registers. */ | | 995 | /* Clear the tally registers. */ |
994 | CSR_WRITE(sc, SONIC_CRCETC, 0xffff); | | 996 | CSR_WRITE(sc, SONIC_CRCETC, 0xffff); |
995 | CSR_WRITE(sc, SONIC_FAET, 0xffff); | | 997 | CSR_WRITE(sc, SONIC_FAET, 0xffff); |
996 | CSR_WRITE(sc, SONIC_MPT, 0xffff); | | 998 | CSR_WRITE(sc, SONIC_MPT, 0xffff); |
997 | | | 999 | |
998 | /* Set the receive filter. */ | | 1000 | /* Set the receive filter. */ |
999 | sonic_set_filter(sc); | | 1001 | sonic_set_filter(sc); |
1000 | | | 1002 | |
1001 | /* | | 1003 | /* |
1002 | * Set the interrupt mask register. | | 1004 | * Set the interrupt mask register. |
1003 | */ | | 1005 | */ |
1004 | sc->sc_imr = IMR_RFO | IMR_RBA | IMR_RBE | IMR_RDE | | | 1006 | sc->sc_imr = IMR_RFO | IMR_RBA | IMR_RBE | IMR_RDE | |
1005 | IMR_TXER | IMR_PTX | IMR_PRX; | | 1007 | IMR_TXER | IMR_PTX | IMR_PRX; |
1006 | CSR_WRITE(sc, SONIC_IMR, sc->sc_imr); | | 1008 | CSR_WRITE(sc, SONIC_IMR, sc->sc_imr); |
1007 | | | 1009 | |
1008 | /* | | 1010 | /* |
1009 | * Start the receive process in motion. Note, we don't | | 1011 | * Start the receive process in motion. Note, we don't |
1010 | * start the transmit process until we actually try to | | 1012 | * start the transmit process until we actually try to |
1011 | * transmit packets. | | 1013 | * transmit packets. |
1012 | */ | | 1014 | */ |
1013 | CSR_WRITE(sc, SONIC_CR, CR_RXEN | CR_RRRA); | | 1015 | CSR_WRITE(sc, SONIC_CR, CR_RXEN | CR_RRRA); |
1014 | | | 1016 | |
1015 | /* | | 1017 | /* |
1016 | * ...all done! | | 1018 | * ...all done! |
1017 | */ | | 1019 | */ |
1018 | ifp->if_flags |= IFF_RUNNING; | | 1020 | ifp->if_flags |= IFF_RUNNING; |
1019 | ifp->if_flags &= ~IFF_OACTIVE; | | 1021 | ifp->if_flags &= ~IFF_OACTIVE; |
1020 | | | 1022 | |
1021 | out: | | 1023 | out: |
1022 | if (error) | | 1024 | if (error) |
1023 | printf("%s: interface not running\n", device_xname(sc->sc_dev)); | | 1025 | printf("%s: interface not running\n", device_xname(sc->sc_dev)); |
1024 | return error; | | 1026 | return error; |
1025 | } | | 1027 | } |
1026 | | | 1028 | |
1027 | /* | | 1029 | /* |
1028 | * sonic_rxdrain: | | 1030 | * sonic_rxdrain: |
1029 | * | | 1031 | * |
1030 | * Drain the receive queue. | | 1032 | * Drain the receive queue. |
1031 | */ | | 1033 | */ |
1032 | void | | 1034 | void |
1033 | sonic_rxdrain(struct sonic_softc *sc) | | 1035 | sonic_rxdrain(struct sonic_softc *sc) |
1034 | { | | 1036 | { |
1035 | struct sonic_descsoft *ds; | | 1037 | struct sonic_descsoft *ds; |
1036 | int i; | | 1038 | int i; |
1037 | | | 1039 | |
1038 | for (i = 0; i < SONIC_NRXDESC; i++) { | | 1040 | for (i = 0; i < SONIC_NRXDESC; i++) { |
1039 | ds = &sc->sc_rxsoft[i]; | | 1041 | ds = &sc->sc_rxsoft[i]; |
1040 | if (ds->ds_mbuf != NULL) { | | 1042 | if (ds->ds_mbuf != NULL) { |
1041 | bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap); | | 1043 | bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap); |
1042 | m_freem(ds->ds_mbuf); | | 1044 | m_freem(ds->ds_mbuf); |
1043 | ds->ds_mbuf = NULL; | | 1045 | ds->ds_mbuf = NULL; |
1044 | } | | 1046 | } |
1045 | } | | 1047 | } |
1046 | } | | 1048 | } |
1047 | | | 1049 | |
1048 | /* | | 1050 | /* |
1049 | * sonic_stop: [ifnet interface function] | | 1051 | * sonic_stop: [ifnet interface function] |
1050 | * | | 1052 | * |
1051 | * Stop transmission on the interface. | | 1053 | * Stop transmission on the interface. |
1052 | */ | | 1054 | */ |
1053 | void | | 1055 | void |
1054 | sonic_stop(struct ifnet *ifp, int disable) | | 1056 | sonic_stop(struct ifnet *ifp, int disable) |
1055 | { | | 1057 | { |
1056 | struct sonic_softc *sc = ifp->if_softc; | | 1058 | struct sonic_softc *sc = ifp->if_softc; |
1057 | struct sonic_descsoft *ds; | | 1059 | struct sonic_descsoft *ds; |
1058 | int i; | | 1060 | int i; |
1059 | | | 1061 | |
1060 | /* | | 1062 | /* |
1061 | * Disable interrupts. | | 1063 | * Disable interrupts. |
1062 | */ | | 1064 | */ |
1063 | CSR_WRITE(sc, SONIC_IMR, 0); | | 1065 | CSR_WRITE(sc, SONIC_IMR, 0); |
1064 | | | 1066 | |
1065 | /* | | 1067 | /* |
1066 | * Stop the transmitter, receiver, and timer. | | 1068 | * Stop the transmitter, receiver, and timer. |
1067 | */ | | 1069 | */ |
1068 | CSR_WRITE(sc, SONIC_CR, CR_HTX|CR_RXDIS|CR_STP); | | 1070 | CSR_WRITE(sc, SONIC_CR, CR_HTX|CR_RXDIS|CR_STP); |
1069 | for (i = 0; i < 1000; i++) { | | 1071 | for (i = 0; i < 1000; i++) { |
1070 | if ((CSR_READ(sc, SONIC_CR) & (CR_TXP|CR_RXEN|CR_ST)) == 0) | | 1072 | if ((CSR_READ(sc, SONIC_CR) & (CR_TXP|CR_RXEN|CR_ST)) == 0) |
1071 | break; | | 1073 | break; |
1072 | delay(2); | | 1074 | delay(2); |
1073 | } | | 1075 | } |
1074 | if ((CSR_READ(sc, SONIC_CR) & (CR_TXP|CR_RXEN|CR_ST)) != 0) | | 1076 | if ((CSR_READ(sc, SONIC_CR) & (CR_TXP|CR_RXEN|CR_ST)) != 0) |
1075 | printf("%s: SONIC failed to stop\n", device_xname(sc->sc_dev)); | | 1077 | printf("%s: SONIC failed to stop\n", device_xname(sc->sc_dev)); |
1076 | | | 1078 | |
1077 | /* | | 1079 | /* |
1078 | * Release any queued transmit buffers. | | 1080 | * Release any queued transmit buffers. |
1079 | */ | | 1081 | */ |
1080 | for (i = 0; i < SONIC_NTXDESC; i++) { | | 1082 | for (i = 0; i < SONIC_NTXDESC; i++) { |
1081 | ds = &sc->sc_txsoft[i]; | | 1083 | ds = &sc->sc_txsoft[i]; |
1082 | if (ds->ds_mbuf != NULL) { | | 1084 | if (ds->ds_mbuf != NULL) { |
1083 | bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap); | | 1085 | bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap); |
1084 | m_freem(ds->ds_mbuf); | | 1086 | m_freem(ds->ds_mbuf); |
1085 | ds->ds_mbuf = NULL; | | 1087 | ds->ds_mbuf = NULL; |
1086 | } | | 1088 | } |
1087 | } | | 1089 | } |
1088 | | | 1090 | |
1089 | /* | | 1091 | /* |
1090 | * Mark the interface down and cancel the watchdog timer. | | 1092 | * Mark the interface down and cancel the watchdog timer. |
1091 | */ | | 1093 | */ |
1092 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); | | 1094 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); |
1093 | ifp->if_timer = 0; | | 1095 | ifp->if_timer = 0; |
1094 | | | 1096 | |
1095 | if (disable) | | 1097 | if (disable) |
1096 | sonic_rxdrain(sc); | | 1098 | sonic_rxdrain(sc); |
1097 | } | | 1099 | } |
1098 | | | 1100 | |
1099 | /* | | 1101 | /* |
1100 | * sonic_add_rxbuf: | | 1102 | * sonic_add_rxbuf: |
1101 | * | | 1103 | * |
1102 | * Add a receive buffer to the indicated descriptor. | | 1104 | * Add a receive buffer to the indicated descriptor. |
1103 | */ | | 1105 | */ |
1104 | int | | 1106 | int |
1105 | sonic_add_rxbuf(struct sonic_softc *sc, int idx) | | 1107 | sonic_add_rxbuf(struct sonic_softc *sc, int idx) |
1106 | { | | 1108 | { |
1107 | struct sonic_descsoft *ds = &sc->sc_rxsoft[idx]; | | 1109 | struct sonic_descsoft *ds = &sc->sc_rxsoft[idx]; |
1108 | struct mbuf *m; | | 1110 | struct mbuf *m; |
1109 | int error; | | 1111 | int error; |
1110 | | | 1112 | |
1111 | MGETHDR(m, M_DONTWAIT, MT_DATA); | | 1113 | MGETHDR(m, M_DONTWAIT, MT_DATA); |
1112 | if (m == NULL) | | 1114 | if (m == NULL) |
1113 | return ENOBUFS; | | 1115 | return ENOBUFS; |
1114 | | | 1116 | |
1115 | MCLGET(m, M_DONTWAIT); | | 1117 | MCLGET(m, M_DONTWAIT); |
1116 | if ((m->m_flags & M_EXT) == 0) { | | 1118 | if ((m->m_flags & M_EXT) == 0) { |
1117 | m_freem(m); | | 1119 | m_freem(m); |
1118 | return ENOBUFS; | | 1120 | return ENOBUFS; |
1119 | } | | 1121 | } |
1120 | | | 1122 | |
1121 | if (ds->ds_mbuf != NULL) | | 1123 | if (ds->ds_mbuf != NULL) |
1122 | bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap); | | 1124 | bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap); |
1123 | | | 1125 | |
1124 | ds->ds_mbuf = m; | | 1126 | ds->ds_mbuf = m; |
1125 | | | 1127 | |
1126 | error = bus_dmamap_load(sc->sc_dmat, ds->ds_dmamap, | | 1128 | error = bus_dmamap_load(sc->sc_dmat, ds->ds_dmamap, |
1127 | m->m_ext.ext_buf, m->m_ext.ext_size, NULL, | | 1129 | m->m_ext.ext_buf, m->m_ext.ext_size, NULL, |
1128 | BUS_DMA_READ|BUS_DMA_NOWAIT); | | 1130 | BUS_DMA_READ|BUS_DMA_NOWAIT); |
1129 | if (error) { | | 1131 | if (error) { |
1130 | printf("%s: can't load rx DMA map %d, error = %d\n", | | 1132 | printf("%s: can't load rx DMA map %d, error = %d\n", |
1131 | device_xname(sc->sc_dev), idx, error); | | 1133 | device_xname(sc->sc_dev), idx, error); |
1132 | panic("sonic_add_rxbuf"); /* XXX */ | | 1134 | panic("sonic_add_rxbuf"); /* XXX */ |
1133 | } | | 1135 | } |
1134 | | | 1136 | |
1135 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, | | 1137 | bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0, |
1136 | ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); | | 1138 | ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD); |
1137 | | | 1139 | |
1138 | SONIC_INIT_RXDESC(sc, idx); | | 1140 | SONIC_INIT_RXDESC(sc, idx); |
1139 | | | 1141 | |
1140 | return 0; | | 1142 | return 0; |
1141 | } | | 1143 | } |
1142 | | | 1144 | |
1143 | static void | | 1145 | static void |
1144 | sonic_set_camentry(struct sonic_softc *sc, int entry, const uint8_t *enaddr) | | 1146 | sonic_set_camentry(struct sonic_softc *sc, int entry, const uint8_t *enaddr) |
1145 | { | | 1147 | { |
1146 | | | 1148 | |
1147 | if (sc->sc_32bit) { | | 1149 | if (sc->sc_32bit) { |
1148 | struct sonic_cda32 *cda = &sc->sc_cda32[entry]; | | 1150 | struct sonic_cda32 *cda = &sc->sc_cda32[entry]; |
1149 | | | 1151 | |
1150 | cda->cda_entry = htosonic32(sc, entry); | | 1152 | cda->cda_entry = htosonic32(sc, entry); |
1151 | cda->cda_addr0 = htosonic32(sc, enaddr[0] | (enaddr[1] << 8)); | | 1153 | cda->cda_addr0 = htosonic32(sc, enaddr[0] | (enaddr[1] << 8)); |
1152 | cda->cda_addr1 = htosonic32(sc, enaddr[2] | (enaddr[3] << 8)); | | 1154 | cda->cda_addr1 = htosonic32(sc, enaddr[2] | (enaddr[3] << 8)); |
1153 | cda->cda_addr2 = htosonic32(sc, enaddr[4] | (enaddr[5] << 8)); | | 1155 | cda->cda_addr2 = htosonic32(sc, enaddr[4] | (enaddr[5] << 8)); |
1154 | } else { | | 1156 | } else { |
1155 | struct sonic_cda16 *cda = &sc->sc_cda16[entry]; | | 1157 | struct sonic_cda16 *cda = &sc->sc_cda16[entry]; |
1156 | | | 1158 | |
1157 | cda->cda_entry = htosonic16(sc, entry); | | 1159 | cda->cda_entry = htosonic16(sc, entry); |
1158 | cda->cda_addr0 = htosonic16(sc, enaddr[0] | (enaddr[1] << 8)); | | 1160 | cda->cda_addr0 = htosonic16(sc, enaddr[0] | (enaddr[1] << 8)); |
1159 | cda->cda_addr1 = htosonic16(sc, enaddr[2] | (enaddr[3] << 8)); | | 1161 | cda->cda_addr1 = htosonic16(sc, enaddr[2] | (enaddr[3] << 8)); |
1160 | cda->cda_addr2 = htosonic16(sc, enaddr[4] | (enaddr[5] << 8)); | | 1162 | cda->cda_addr2 = htosonic16(sc, enaddr[4] | (enaddr[5] << 8)); |
1161 | } | | 1163 | } |
1162 | } | | 1164 | } |
1163 | | | 1165 | |
1164 | /* | | 1166 | /* |
1165 | * sonic_set_filter: | | 1167 | * sonic_set_filter: |
1166 | * | | 1168 | * |
1167 | * Set the SONIC receive filter. | | 1169 | * Set the SONIC receive filter. |
1168 | */ | | 1170 | */ |
1169 | void | | 1171 | void |
1170 | sonic_set_filter(struct sonic_softc *sc) | | 1172 | sonic_set_filter(struct sonic_softc *sc) |
1171 | { | | 1173 | { |
1172 | struct ethercom *ec = &sc->sc_ethercom; | | 1174 | struct ethercom *ec = &sc->sc_ethercom; |
1173 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | | 1175 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
1174 | struct ether_multi *enm; | | 1176 | struct ether_multi *enm; |
1175 | struct ether_multistep step; | | 1177 | struct ether_multistep step; |
1176 | int i, entry = 0; | | 1178 | int i, entry = 0; |
1177 | uint16_t camvalid = 0; | | 1179 | uint16_t camvalid = 0; |
1178 | uint16_t rcr = 0; | | 1180 | uint16_t rcr = 0; |
1179 | | | 1181 | |
1180 | if (ifp->if_flags & IFF_BROADCAST) | | 1182 | if (ifp->if_flags & IFF_BROADCAST) |
1181 | rcr |= RCR_BRD; | | 1183 | rcr |= RCR_BRD; |
1182 | | | 1184 | |
1183 | if (ifp->if_flags & IFF_PROMISC) { | | 1185 | if (ifp->if_flags & IFF_PROMISC) { |
1184 | rcr |= RCR_PRO; | | 1186 | rcr |= RCR_PRO; |
1185 | goto allmulti; | | 1187 | goto allmulti; |
1186 | } | | 1188 | } |
1187 | | | 1189 | |
1188 | /* Put our station address in the first CAM slot. */ | | 1190 | /* Put our station address in the first CAM slot. */ |
1189 | sonic_set_camentry(sc, entry, CLLADDR(ifp->if_sadl)); | | 1191 | sonic_set_camentry(sc, entry, CLLADDR(ifp->if_sadl)); |
1190 | camvalid |= (1U << entry); | | 1192 | camvalid |= (1U << entry); |
1191 | entry++; | | 1193 | entry++; |
1192 | | | 1194 | |
1193 | /* Add the multicast addresses to the CAM. */ | | 1195 | /* Add the multicast addresses to the CAM. */ |
1194 | ETHER_FIRST_MULTI(step, ec, enm); | | 1196 | ETHER_FIRST_MULTI(step, ec, enm); |
1195 | while (enm != NULL) { | | 1197 | while (enm != NULL) { |
1196 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | | 1198 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { |
1197 | /* | | 1199 | /* |
1198 | * We must listen to a range of multicast addresses. | | 1200 | * We must listen to a range of multicast addresses. |
1199 | * The only way to do this on the SONIC is to enable | | 1201 | * The only way to do this on the SONIC is to enable |
1200 | * reception of all multicast packets. | | 1202 | * reception of all multicast packets. |
1201 | */ | | 1203 | */ |
1202 | goto allmulti; | | 1204 | goto allmulti; |
1203 | } | | 1205 | } |
1204 | | | 1206 | |
1205 | if (entry == SONIC_NCAMENT) { | | 1207 | if (entry == SONIC_NCAMENT) { |
1206 | /* | | 1208 | /* |
1207 | * Out of CAM slots. Have to enable reception | | 1209 | * Out of CAM slots. Have to enable reception |
1208 | * of all multicast addresses. | | 1210 | * of all multicast addresses. |
1209 | */ | | 1211 | */ |
1210 | goto allmulti; | | 1212 | goto allmulti; |
1211 | } | | 1213 | } |
1212 | | | 1214 | |
1213 | sonic_set_camentry(sc, entry, enm->enm_addrlo); | | 1215 | sonic_set_camentry(sc, entry, enm->enm_addrlo); |
1214 | camvalid |= (1U << entry); | | 1216 | camvalid |= (1U << entry); |
1215 | entry++; | | 1217 | entry++; |
1216 | | | 1218 | |
1217 | ETHER_NEXT_MULTI(step, enm); | | 1219 | ETHER_NEXT_MULTI(step, enm); |
1218 | } | | 1220 | } |
1219 | | | 1221 | |
1220 | ifp->if_flags &= ~IFF_ALLMULTI; | | 1222 | ifp->if_flags &= ~IFF_ALLMULTI; |
1221 | goto setit; | | 1223 | goto setit; |
1222 | | | 1224 | |
1223 | allmulti: | | 1225 | allmulti: |
1224 | /* Use only the first CAM slot (station address). */ | | 1226 | /* Use only the first CAM slot (station address). */ |
1225 | camvalid = 0x0001; | | 1227 | camvalid = 0x0001; |
1226 | entry = 1; | | 1228 | entry = 1; |
1227 | rcr |= RCR_AMC; | | 1229 | rcr |= RCR_AMC; |
1228 | | | 1230 | |
1229 | setit: | | 1231 | setit: |
1230 | /* set mask for the CAM Enable register */ | | 1232 | /* set mask for the CAM Enable register */ |
1231 | if (sc->sc_32bit) { | | 1233 | if (sc->sc_32bit) { |
1232 | if (entry == SONIC_NCAMENT) | | 1234 | if (entry == SONIC_NCAMENT) |
1233 | sc->sc_cdaenable32 = htosonic32(sc, camvalid); | | 1235 | sc->sc_cdaenable32 = htosonic32(sc, camvalid); |
1234 | else | | 1236 | else |
1235 | sc->sc_cda32[entry].cda_entry = | | 1237 | sc->sc_cda32[entry].cda_entry = |
1236 | htosonic32(sc, camvalid); | | 1238 | htosonic32(sc, camvalid); |
1237 | } else { | | 1239 | } else { |
1238 | if (entry == SONIC_NCAMENT) | | 1240 | if (entry == SONIC_NCAMENT) |
1239 | sc->sc_cdaenable16 = htosonic16(sc, camvalid); | | 1241 | sc->sc_cdaenable16 = htosonic16(sc, camvalid); |
1240 | else | | 1242 | else |
1241 | sc->sc_cda16[entry].cda_entry = | | 1243 | sc->sc_cda16[entry].cda_entry = |
1242 | htosonic16(sc, camvalid); | | 1244 | htosonic16(sc, camvalid); |
1243 | } | | 1245 | } |
1244 | | | 1246 | |
1245 | /* Load the CAM. */ | | 1247 | /* Load the CAM. */ |
1246 | SONIC_CDCAMSYNC(sc, BUS_DMASYNC_PREWRITE); | | 1248 | SONIC_CDCAMSYNC(sc, BUS_DMASYNC_PREWRITE); |
1247 | CSR_WRITE(sc, SONIC_CDP, SONIC_CDCAMADDR(sc) & 0xffff); | | 1249 | CSR_WRITE(sc, SONIC_CDP, SONIC_CDCAMADDR(sc) & 0xffff); |
1248 | CSR_WRITE(sc, SONIC_CDC, entry); | | 1250 | CSR_WRITE(sc, SONIC_CDC, entry); |
1249 | CSR_WRITE(sc, SONIC_CR, CR_LCAM); | | 1251 | CSR_WRITE(sc, SONIC_CR, CR_LCAM); |
1250 | for (i = 0; i < 10000; i++) { | | 1252 | for (i = 0; i < 10000; i++) { |
1251 | if ((CSR_READ(sc, SONIC_CR) & CR_LCAM) == 0) | | 1253 | if ((CSR_READ(sc, SONIC_CR) & CR_LCAM) == 0) |
1252 | break; | | 1254 | break; |
1253 | delay(2); | | 1255 | delay(2); |
1254 | } | | 1256 | } |
1255 | if (CSR_READ(sc, SONIC_CR) & CR_LCAM) | | 1257 | if (CSR_READ(sc, SONIC_CR) & CR_LCAM) |
1256 | printf("%s: CAM load failed\n", device_xname(sc->sc_dev)); | | 1258 | printf("%s: CAM load failed\n", device_xname(sc->sc_dev)); |
1257 | SONIC_CDCAMSYNC(sc, BUS_DMASYNC_POSTWRITE); | | 1259 | SONIC_CDCAMSYNC(sc, BUS_DMASYNC_POSTWRITE); |
1258 | | | 1260 | |
1259 | /* Set the receive control register. */ | | 1261 | /* Set the receive control register. */ |
1260 | CSR_WRITE(sc, SONIC_RCR, rcr); | | 1262 | CSR_WRITE(sc, SONIC_RCR, rcr); |
1261 | } | | 1263 | } |