mb86950.c revision 1.13 1 1.13 dsl /* $NetBSD: mb86950.c,v 1.13 2009/03/14 14:46:08 dsl Exp $ */
2 1.1 jdolecek
3 1.1 jdolecek /*
4 1.1 jdolecek * All Rights Reserved, Copyright (C) Fujitsu Limited 1995
5 1.1 jdolecek *
6 1.1 jdolecek * This software may be used, modified, copied, distributed, and sold, in
7 1.1 jdolecek * both source and binary form provided that the above copyright, these
8 1.1 jdolecek * terms and the following disclaimer are retained. The name of the author
9 1.1 jdolecek * and/or the contributor may not be used to endorse or promote products
10 1.1 jdolecek * derived from this software without specific prior written permission.
11 1.1 jdolecek *
12 1.1 jdolecek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND THE CONTRIBUTOR ``AS IS'' AND
13 1.1 jdolecek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14 1.1 jdolecek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15 1.1 jdolecek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE CONTRIBUTOR BE LIABLE
16 1.1 jdolecek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17 1.1 jdolecek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18 1.1 jdolecek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION.
19 1.1 jdolecek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20 1.1 jdolecek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21 1.1 jdolecek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22 1.1 jdolecek * SUCH DAMAGE.
23 1.1 jdolecek */
24 1.1 jdolecek
25 1.1 jdolecek /*
26 1.1 jdolecek * Portions copyright (C) 1993, David Greenman. This software may be used,
27 1.1 jdolecek * modified, copied, distributed, and sold, in both source and binary form
28 1.1 jdolecek * provided that the above copyright and these terms are retained. Under no
29 1.1 jdolecek * circumstances is the author responsible for the proper functioning of this
30 1.1 jdolecek * software, nor does the author assume any responsibility for damages
31 1.1 jdolecek * incurred with its use.
32 1.1 jdolecek */
33 1.1 jdolecek
34 1.1 jdolecek /*
35 1.1 jdolecek * Portions copyright (c) 1995 Mika Kortelainen
36 1.1 jdolecek * All rights reserved.
37 1.1 jdolecek *
38 1.1 jdolecek * Redistribution and use in source and binary forms, with or without
39 1.1 jdolecek * modification, are permitted provided that the following conditions
40 1.1 jdolecek * are met:
41 1.1 jdolecek * 1. Redistributions of source code must retain the above copyright
42 1.1 jdolecek * notice, this list of conditions and the following disclaimer.
43 1.1 jdolecek * 2. Redistributions in binary form must reproduce the above copyright
44 1.1 jdolecek * notice, this list of conditions and the following disclaimer in the
45 1.1 jdolecek * documentation and/or other materials provided with the distribution.
46 1.1 jdolecek * 3. All advertising materials mentioning features or use of this software
47 1.1 jdolecek * must display the following acknowledgement:
48 1.1 jdolecek * This product includes software developed by Mika Kortelainen
49 1.1 jdolecek * 4. The name of the author may not be used to endorse or promote products
50 1.1 jdolecek * derived from this software without specific prior written permission
51 1.1 jdolecek *
52 1.1 jdolecek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
53 1.1 jdolecek * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
54 1.1 jdolecek * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
55 1.1 jdolecek * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
56 1.1 jdolecek * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
57 1.1 jdolecek * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
58 1.1 jdolecek * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
59 1.1 jdolecek * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60 1.1 jdolecek * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
61 1.1 jdolecek * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62 1.1 jdolecek */
63 1.1 jdolecek
64 1.1 jdolecek /*
65 1.1 jdolecek * Device driver for Fujitsu MB86960A/MB86965A based Ethernet cards.
66 1.1 jdolecek * Contributed by M.S. <seki (at) sysrap.cs.fujitsu.co.jp>
67 1.1 jdolecek */
68 1.1 jdolecek
69 1.1 jdolecek #include <sys/cdefs.h>
70 1.13 dsl __KERNEL_RCSID(0, "$NetBSD: mb86950.c,v 1.13 2009/03/14 14:46:08 dsl Exp $");
71 1.1 jdolecek
72 1.1 jdolecek /*
73 1.1 jdolecek * Device driver for Fujitsu mb86950 based Ethernet cards.
74 1.1 jdolecek * Adapted by Dave J. Barnes from various Internet sources including
75 1.1 jdolecek * mb86960.c (NetBSD), if_qn.c (NetBSD/Amiga), DOS Packet Driver (Brian Fisher,
76 1.1 jdolecek * Queens University), EtherBoot Driver (Ken Yap).
77 1.1 jdolecek */
78 1.1 jdolecek
79 1.1 jdolecek /* XXX There are still rough edges......
80 1.2 jdolecek *
81 1.1 jdolecek * (1) There is no watchdog timer for the transmitter. It's doubtful that
82 1.2 jdolecek * transmit from the chip could be restarted without a hardware reset
83 1.2 jdolecek * though. (Fixed - not fully tested)
84 1.2 jdolecek *
85 1.1 jdolecek * (2) The media interface callback goo is broke. No big deal since to change
86 1.2 jdolecek * from aui to bnc on the old Tiara LANCard requires moving 8 board jumpers.
87 1.2 jdolecek * Other cards (SMC ?) using the EtherStar chip may support media change
88 1.2 jdolecek * via software. (Fixed - tested)
89 1.2 jdolecek *
90 1.2 jdolecek * (3) The maximum outstanding transmit packets is set to 4. What
91 1.2 jdolecek * is a good limit of outstanding transmit packets for the EtherStar?
92 1.2 jdolecek * Is there a way to tell how many bytes are remaining to be
93 1.2 jdolecek * transmitted? [no]
94 1.1 jdolecek ---
95 1.2 jdolecek When the EtherStar was designed, CPU power was a fraction
96 1.2 jdolecek of what it is now. The single EtherStar transmit buffer
97 1.2 jdolecek was fine. It was unlikely that the CPU could outrun the
98 1.2 jdolecek EtherStar. However, things in 2004 are quite different.
99 1.2 jdolecek sc->txb_size is used to keep the CPU from overrunning the
100 1.2 jdolecek EtherStar. At most allow one packet transmitting and one
101 1.2 jdolecek going into the fifo.
102 1.2 jdolecek
103 1.1 jdolecek ---
104 1.1 jdolecek No, that isn't right either :(
105 1.1 jdolecek
106 1.2 jdolecek * (4) Multicast isn't supported. Feel free to add multicast code
107 1.2 jdolecek * if you know how to make the EtherStar do multicast. Otherwise
108 1.2 jdolecek * you'd have to use promiscuous mode and do multicast in software. OUCH!
109 1.2 jdolecek *
110 1.1 jdolecek * (5) There are no bus_space_barrier calls used. Are they needed? Maybe not.
111 1.2 jdolecek *
112 1.2 jdolecek * (6) Access to the fifo assumes word (16 bit) mode. Cards configured for
113 1.2 jdolecek * byte wide fifo access will require driver code changes.
114 1.2 jdolecek *
115 1.2 jdolecek * Only the minimum code necessary to make the Tiara LANCard work
116 1.2 jdolecek * has been tested. Other cards may require more work, especially
117 1.2 jdolecek * byte mode fifo and if DMA is used.
118 1.2 jdolecek *
119 1.1 jdolecek * djb / 2004
120 1.1 jdolecek */
121 1.1 jdolecek
122 1.1 jdolecek #include "opt_inet.h"
123 1.1 jdolecek #include "bpfilter.h"
124 1.1 jdolecek #include "rnd.h"
125 1.1 jdolecek
126 1.1 jdolecek #include <sys/param.h>
127 1.1 jdolecek #include <sys/systm.h>
128 1.1 jdolecek #include <sys/errno.h>
129 1.1 jdolecek #include <sys/ioctl.h>
130 1.1 jdolecek #include <sys/mbuf.h>
131 1.1 jdolecek #include <sys/socket.h>
132 1.1 jdolecek #include <sys/syslog.h>
133 1.1 jdolecek #include <sys/device.h>
134 1.1 jdolecek #if NRND > 0
135 1.1 jdolecek #include <sys/rnd.h>
136 1.1 jdolecek #endif
137 1.1 jdolecek
138 1.1 jdolecek #include <net/if.h>
139 1.1 jdolecek #include <net/if_dl.h>
140 1.1 jdolecek #include <net/if_types.h>
141 1.1 jdolecek #include <net/if_media.h>
142 1.1 jdolecek #include <net/if_ether.h>
143 1.1 jdolecek
144 1.1 jdolecek #ifdef INET
145 1.1 jdolecek #include <netinet/in.h>
146 1.1 jdolecek #include <netinet/in_systm.h>
147 1.1 jdolecek #include <netinet/in_var.h>
148 1.1 jdolecek #include <netinet/ip.h>
149 1.1 jdolecek #include <netinet/if_inarp.h>
150 1.1 jdolecek #endif
151 1.1 jdolecek
152 1.1 jdolecek
153 1.1 jdolecek #if NBPFILTER > 0
154 1.1 jdolecek #include <net/bpf.h>
155 1.1 jdolecek #include <net/bpfdesc.h>
156 1.1 jdolecek #endif
157 1.1 jdolecek
158 1.10 ad #include <sys/bus.h>
159 1.1 jdolecek
160 1.1 jdolecek #include <dev/ic/mb86950reg.h>
161 1.1 jdolecek #include <dev/ic/mb86950var.h>
162 1.1 jdolecek
163 1.1 jdolecek #ifndef __BUS_SPACE_HAS_STREAM_METHODS
164 1.1 jdolecek #define bus_space_write_stream_2 bus_space_write_2
165 1.1 jdolecek #define bus_space_write_multi_stream_2 bus_space_write_multi_2
166 1.1 jdolecek #define bus_space_read_multi_stream_2 bus_space_read_multi_2
167 1.1 jdolecek #endif /* __BUS_SPACE_HAS_STREAM_METHODS */
168 1.1 jdolecek
169 1.1 jdolecek /* Standard driver entry points. These can be static. */
170 1.13 dsl int mb86950_ioctl(struct ifnet *, u_long, void *);
171 1.13 dsl void mb86950_init(struct mb86950_softc *);
172 1.13 dsl void mb86950_start(struct ifnet *);
173 1.13 dsl void mb86950_watchdog(struct ifnet *);
174 1.13 dsl void mb86950_reset(struct mb86950_softc *);
175 1.1 jdolecek
176 1.1 jdolecek /* Local functions. */
177 1.13 dsl void mb86950_stop(struct mb86950_softc *);
178 1.13 dsl void mb86950_tint(struct mb86950_softc *, u_int8_t);
179 1.13 dsl void mb86950_rint(struct mb86950_softc *, u_int8_t);
180 1.13 dsl int mb86950_get_fifo(struct mb86950_softc *, u_int);
181 1.13 dsl ushort mb86950_put_fifo(struct mb86950_softc *, struct mbuf *);
182 1.13 dsl void mb86950_drain_fifo(struct mb86950_softc *);
183 1.1 jdolecek
184 1.13 dsl int mb86950_mediachange(struct ifnet *);
185 1.13 dsl void mb86950_mediastatus(struct ifnet *, struct ifmediareq *);
186 1.1 jdolecek
187 1.1 jdolecek
188 1.1 jdolecek #if ESTAR_DEBUG >= 1
189 1.13 dsl void mb86950_dump(int, struct mb86950_softc *);
190 1.1 jdolecek #endif
191 1.1 jdolecek
192 1.1 jdolecek /********************************************************************/
193 1.1 jdolecek
194 1.1 jdolecek void
195 1.1 jdolecek mb86950_attach(sc, myea)
196 1.1 jdolecek struct mb86950_softc *sc;
197 1.1 jdolecek u_int8_t *myea;
198 1.1 jdolecek {
199 1.1 jdolecek
200 1.1 jdolecek #ifdef DIAGNOSTIC
201 1.1 jdolecek if (myea == NULL) {
202 1.1 jdolecek printf("%s: ethernet address shouldn't be NULL\n",
203 1.11 cegger device_xname(&sc->sc_dev));
204 1.1 jdolecek panic("NULL ethernet address");
205 1.1 jdolecek }
206 1.1 jdolecek #endif
207 1.1 jdolecek
208 1.1 jdolecek /* Initialize 86950. */
209 1.1 jdolecek mb86950_stop(sc);
210 1.1 jdolecek
211 1.1 jdolecek memcpy(sc->sc_enaddr, myea, sizeof(sc->sc_enaddr));
212 1.1 jdolecek
213 1.1 jdolecek sc->sc_stat |= ESTAR_STAT_ENABLED;
214 1.1 jdolecek }
215 1.1 jdolecek
216 1.1 jdolecek /*
217 1.1 jdolecek * Stop everything on the interface.
218 1.1 jdolecek *
219 1.1 jdolecek * All buffered packets, both transmitting and receiving,
220 1.1 jdolecek * if any, will be lost by stopping the interface.
221 1.1 jdolecek */
222 1.1 jdolecek void
223 1.1 jdolecek mb86950_stop(sc)
224 1.1 jdolecek struct mb86950_softc *sc;
225 1.1 jdolecek {
226 1.1 jdolecek bus_space_tag_t bst = sc->sc_bst;
227 1.1 jdolecek bus_space_handle_t bsh = sc->sc_bsh;
228 1.1 jdolecek
229 1.1 jdolecek /* Stop interface hardware. */
230 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_CONFIG, DISABLE_DLC);
231 1.1 jdolecek delay(200);
232 1.1 jdolecek
233 1.1 jdolecek /* Disable interrupts. */
234 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, 0);
235 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_RX_INT_EN, 0);
236 1.1 jdolecek
237 1.1 jdolecek /* Ack / Clear all interrupt status. */
238 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_TX_STAT, 0xff);
239 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_RX_STAT, 0xff);
240 1.1 jdolecek
241 1.1 jdolecek /* Clear DMA Bit */
242 1.1 jdolecek bus_space_write_2(bst, bsh, BMPR_DMA, 0);
243 1.1 jdolecek
244 1.1 jdolecek /* accept no packets */
245 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_TX_MODE, 0);
246 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_RX_MODE, 0);
247 1.1 jdolecek
248 1.1 jdolecek mb86950_drain_fifo(sc);
249 1.1 jdolecek
250 1.1 jdolecek }
251 1.1 jdolecek
252 1.1 jdolecek void
253 1.1 jdolecek mb86950_drain_fifo(sc)
254 1.1 jdolecek struct mb86950_softc *sc;
255 1.1 jdolecek {
256 1.1 jdolecek bus_space_tag_t bst = sc->sc_bst;
257 1.1 jdolecek bus_space_handle_t bsh = sc->sc_bsh;
258 1.1 jdolecek
259 1.1 jdolecek /* Read data until bus read error (i.e. buffer empty). */
260 1.2 jdolecek /* XXX There ought to be a better way, eats CPU and bothers the chip */
261 1.1 jdolecek while (!(bus_space_read_1(bst, bsh, DLCR_RX_STAT) & RX_BUS_RD_ERR))
262 1.1 jdolecek bus_space_read_2(bst, bsh, BMPR_FIFO);
263 1.2 jdolecek /* XXX */
264 1.1 jdolecek
265 1.1 jdolecek /* Clear Bus Rd Error */
266 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_RX_STAT, RX_BUS_RD_ERR);
267 1.1 jdolecek }
268 1.1 jdolecek
269 1.1 jdolecek /*
270 1.1 jdolecek * Install interface into kernel networking data structures
271 1.1 jdolecek */
272 1.1 jdolecek void
273 1.8 christos mb86950_config(struct mb86950_softc *sc, int *media,
274 1.8 christos int nmedia, int defmedia)
275 1.1 jdolecek {
276 1.1 jdolecek struct ifnet *ifp = &sc->sc_ec.ec_if;
277 1.1 jdolecek bus_space_tag_t bst = sc->sc_bst;
278 1.1 jdolecek bus_space_handle_t bsh = sc->sc_bsh;
279 1.1 jdolecek
280 1.1 jdolecek /* Initialize ifnet structure. */
281 1.11 cegger strlcpy(ifp->if_xname, device_xname(&sc->sc_dev), IFNAMSIZ);
282 1.1 jdolecek ifp->if_softc = sc;
283 1.1 jdolecek ifp->if_start = mb86950_start;
284 1.1 jdolecek ifp->if_ioctl = mb86950_ioctl;
285 1.1 jdolecek ifp->if_watchdog = mb86950_watchdog;
286 1.1 jdolecek ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
287 1.1 jdolecek
288 1.1 jdolecek IFQ_SET_READY(&ifp->if_snd);
289 1.1 jdolecek
290 1.1 jdolecek /* Initialize media goo. */
291 1.1 jdolecek /* XXX The Tiara LANCard uses board jumpers to change media.
292 1.1 jdolecek * This code may have to be changed for other cards.
293 1.1 jdolecek */
294 1.1 jdolecek ifmedia_init(&sc->sc_media, 0, mb86950_mediachange, mb86950_mediastatus);
295 1.1 jdolecek ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_MANUAL, 0, NULL);
296 1.1 jdolecek ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_MANUAL);
297 1.1 jdolecek
298 1.1 jdolecek /* Attach the interface. */
299 1.1 jdolecek if_attach(ifp);
300 1.1 jdolecek
301 1.1 jdolecek /* Feed the chip the station address. */
302 1.1 jdolecek bus_space_write_region_1(bst, bsh, DLCR_NODE_ID, sc->sc_enaddr, ETHER_ADDR_LEN);
303 1.1 jdolecek
304 1.1 jdolecek ether_ifattach(ifp, sc->sc_enaddr);
305 1.1 jdolecek
306 1.1 jdolecek #if NRND > 0
307 1.11 cegger rnd_attach_source(&sc->rnd_source, device_xname(&sc->sc_dev),
308 1.1 jdolecek RND_TYPE_NET, 0);
309 1.1 jdolecek #endif
310 1.1 jdolecek
311 1.1 jdolecek /* XXX No! This doesn't work - DLCR6 of the mb86950 is different
312 1.1 jdolecek
313 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_CONFIG, 0x0f);
314 1.1 jdolecek buf_config = bus_space_read_1(bst, bsh, DLCR_CONFIG);
315 1.1 jdolecek
316 1.1 jdolecek sc->txb_count = ((buf_config & 0x0c) ? 2 : 1);
317 1.1 jdolecek sc->txb_size = 1024 * (2 << ((buf_config & 0x0c) ? (((buf_config & 0x0c) >> 2) - 1) : 0));
318 1.1 jdolecek sc->txb_free = (sc->txb_size * sc->txb_count) / 1500;
319 1.1 jdolecek
320 1.1 jdolecek sc->rxb_size = ((8 << (buf_config & 3)) * 1024) - (sc->txb_size * sc->txb_count);
321 1.1 jdolecek sc->rxb_max = sc->rxb_size / 64;
322 1.1 jdolecek
323 1.1 jdolecek printf("mb86950: Buffer Size %dKB with %d transmit buffer(s) %dKB each.\n",
324 1.1 jdolecek (8 << (buf_config & 3)), sc->txb_count, (sc->txb_size / 1024));
325 1.1 jdolecek printf(" Transmit Buffer Space for %d maximum sized packet(s).\n",sc->txb_free);
326 1.1 jdolecek printf(" System Bus Width %d bits, Buffer Memory %d bits.\n",
327 1.1 jdolecek ((buf_config & 0x20) ? 8 : 16),
328 1.1 jdolecek ((buf_config & 0x10) ? 8 : 16));
329 1.1 jdolecek
330 1.1 jdolecek */
331 1.1 jdolecek
332 1.2 jdolecek /* Set reasonable values for number of packet flow control if not
333 1.2 jdolecek * set elsewhere */
334 1.1 jdolecek if (sc->txb_num_pkt == 0) sc->txb_num_pkt = 1;
335 1.1 jdolecek if (sc->rxb_num_pkt == 0) sc->rxb_num_pkt = 100;
336 1.1 jdolecek
337 1.1 jdolecek /* Print additional info when attached. */
338 1.11 cegger printf("%s: Ethernet address %s\n", device_xname(&sc->sc_dev),
339 1.2 jdolecek ether_sprintf(sc->sc_enaddr));
340 1.1 jdolecek
341 1.1 jdolecek /* The attach is successful. */
342 1.1 jdolecek sc->sc_stat |= ESTAR_STAT_ATTACHED;
343 1.1 jdolecek }
344 1.1 jdolecek
345 1.1 jdolecek /*
346 1.1 jdolecek * Media change callback.
347 1.1 jdolecek */
348 1.1 jdolecek int
349 1.1 jdolecek mb86950_mediachange(ifp)
350 1.1 jdolecek struct ifnet *ifp;
351 1.1 jdolecek {
352 1.1 jdolecek
353 1.1 jdolecek struct mb86950_softc *sc = ifp->if_softc;
354 1.1 jdolecek
355 1.1 jdolecek if (sc->sc_mediachange)
356 1.1 jdolecek return ((*sc->sc_mediachange)(sc));
357 1.1 jdolecek
358 1.1 jdolecek return (0);
359 1.1 jdolecek }
360 1.1 jdolecek
361 1.1 jdolecek /*
362 1.1 jdolecek * Media status callback.
363 1.1 jdolecek */
364 1.1 jdolecek void
365 1.1 jdolecek mb86950_mediastatus(ifp, ifmr)
366 1.1 jdolecek struct ifnet *ifp;
367 1.1 jdolecek struct ifmediareq *ifmr;
368 1.1 jdolecek {
369 1.1 jdolecek struct mb86950_softc *sc = ifp->if_softc;
370 1.1 jdolecek
371 1.1 jdolecek if ((sc->sc_stat & ESTAR_STAT_ENABLED) == 0) {
372 1.1 jdolecek ifmr->ifm_active = IFM_ETHER | IFM_NONE;
373 1.1 jdolecek ifmr->ifm_status = 0;
374 1.1 jdolecek return;
375 1.1 jdolecek }
376 1.1 jdolecek
377 1.1 jdolecek if (sc->sc_mediastatus)
378 1.1 jdolecek (*sc->sc_mediastatus)(sc, ifmr);
379 1.1 jdolecek
380 1.1 jdolecek }
381 1.1 jdolecek
382 1.1 jdolecek /*
383 1.1 jdolecek * Reset interface.
384 1.1 jdolecek */
385 1.1 jdolecek void
386 1.1 jdolecek mb86950_reset(sc)
387 1.1 jdolecek struct mb86950_softc *sc;
388 1.1 jdolecek {
389 1.1 jdolecek int s;
390 1.1 jdolecek
391 1.1 jdolecek s = splnet();
392 1.11 cegger log(LOG_ERR, "%s: device reset\n", device_xname(&sc->sc_dev));
393 1.1 jdolecek mb86950_stop(sc);
394 1.1 jdolecek mb86950_init(sc);
395 1.1 jdolecek splx(s);
396 1.1 jdolecek }
397 1.1 jdolecek
398 1.1 jdolecek /*
399 1.1 jdolecek * Device timeout/watchdog routine. Entered if the device neglects to
400 1.1 jdolecek * generate an interrupt after a transmit has been started on it.
401 1.1 jdolecek */
402 1.1 jdolecek void
403 1.1 jdolecek mb86950_watchdog(ifp)
404 1.1 jdolecek struct ifnet *ifp;
405 1.1 jdolecek {
406 1.1 jdolecek struct mb86950_softc *sc = ifp->if_softc;
407 1.1 jdolecek bus_space_tag_t bst = sc->sc_bst;
408 1.1 jdolecek bus_space_handle_t bsh = sc->sc_bsh;
409 1.1 jdolecek u_int8_t tstat;
410 1.1 jdolecek
411 1.1 jdolecek /* verbose watchdog messages for debugging timeouts */
412 1.1 jdolecek if ((tstat = bus_space_read_1(bst, bsh, DLCR_TX_STAT)) != 0) {
413 1.1 jdolecek if (tstat & TX_CR_LOST) {
414 1.2 jdolecek if ((tstat & (TX_COL | TX_16COL)) == 0) {
415 1.2 jdolecek log(LOG_ERR, "%s: carrier lost\n",
416 1.11 cegger device_xname(&sc->sc_dev));
417 1.2 jdolecek } else {
418 1.2 jdolecek log(LOG_ERR, "%s: excessive collisions\n",
419 1.11 cegger device_xname(&sc->sc_dev));
420 1.2 jdolecek }
421 1.2 jdolecek }
422 1.2 jdolecek else if ((tstat & (TX_UNDERFLO | TX_BUS_WR_ERR)) != 0) {
423 1.2 jdolecek log(LOG_ERR, "%s: tx fifo underflow/overflow\n",
424 1.11 cegger device_xname(&sc->sc_dev));
425 1.2 jdolecek } else {
426 1.2 jdolecek log(LOG_ERR, "%s: transmit error\n",
427 1.11 cegger device_xname(&sc->sc_dev));
428 1.1 jdolecek }
429 1.2 jdolecek } else {
430 1.11 cegger log(LOG_ERR, "%s: device timeout\n", device_xname(&sc->sc_dev));
431 1.1 jdolecek }
432 1.1 jdolecek
433 1.1 jdolecek /* Don't know how many packets are lost by this accident.
434 1.1 jdolecek * ... So just errors = errors + 1
435 1.1 jdolecek */
436 1.1 jdolecek ifp->if_oerrors++;
437 1.1 jdolecek
438 1.1 jdolecek mb86950_reset(sc);
439 1.1 jdolecek
440 1.1 jdolecek }
441 1.1 jdolecek
442 1.1 jdolecek /*
443 1.1 jdolecek ******************** IOCTL
444 1.1 jdolecek * Process an ioctl request.
445 1.1 jdolecek */
446 1.1 jdolecek int
447 1.12 dyoung mb86950_ioctl(struct ifnet *ifp, unsigned long cmd, void *data)
448 1.1 jdolecek {
449 1.1 jdolecek struct mb86950_softc *sc = ifp->if_softc;
450 1.1 jdolecek struct ifaddr *ifa = (struct ifaddr *)data;
451 1.1 jdolecek struct ifreq *ifr = (struct ifreq *)data;
452 1.1 jdolecek
453 1.1 jdolecek int s, error = 0;
454 1.1 jdolecek
455 1.1 jdolecek s = splnet();
456 1.1 jdolecek
457 1.1 jdolecek switch (cmd) {
458 1.12 dyoung case SIOCINITIFADDR:
459 1.12 dyoung /* XXX deprecated ? What should I use instead? */
460 1.1 jdolecek if ((error = mb86950_enable(sc)) != 0)
461 1.1 jdolecek break;
462 1.1 jdolecek
463 1.1 jdolecek ifp->if_flags |= IFF_UP;
464 1.1 jdolecek
465 1.12 dyoung mb86950_init(sc);
466 1.1 jdolecek switch (ifa->ifa_addr->sa_family) {
467 1.1 jdolecek
468 1.1 jdolecek #ifdef INET
469 1.1 jdolecek case AF_INET:
470 1.1 jdolecek arp_ifinit(ifp, ifa);
471 1.1 jdolecek break;
472 1.1 jdolecek #endif
473 1.1 jdolecek
474 1.1 jdolecek
475 1.1 jdolecek default:
476 1.1 jdolecek break;
477 1.1 jdolecek }
478 1.1 jdolecek break;
479 1.1 jdolecek
480 1.1 jdolecek case SIOCSIFFLAGS:
481 1.12 dyoung if ((error = ifioctl_common(ifp, cmd, data)) != 0)
482 1.12 dyoung break;
483 1.12 dyoung /* XXX re-use ether_ioctl() */
484 1.12 dyoung switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) {
485 1.12 dyoung case IFF_RUNNING:
486 1.1 jdolecek /*
487 1.1 jdolecek * If interface is marked down and it is running, then
488 1.1 jdolecek * stop it.
489 1.1 jdolecek */
490 1.1 jdolecek mb86950_stop(sc);
491 1.1 jdolecek ifp->if_flags &= ~IFF_RUNNING;
492 1.1 jdolecek mb86950_disable(sc);
493 1.12 dyoung break;
494 1.12 dyoung case IFF_UP:
495 1.1 jdolecek /*
496 1.1 jdolecek * If interface is marked up and it is stopped, then
497 1.1 jdolecek * start it.
498 1.1 jdolecek */
499 1.1 jdolecek if ((error = mb86950_enable(sc)) != 0)
500 1.1 jdolecek break;
501 1.1 jdolecek mb86950_init(sc);
502 1.12 dyoung break;
503 1.12 dyoung case IFF_UP|IFF_RUNNING:
504 1.1 jdolecek /*
505 1.1 jdolecek * Reset the interface to pick up changes in any other
506 1.1 jdolecek * flags that affect hardware registers.
507 1.1 jdolecek */
508 1.12 dyoung #if 0
509 1.12 dyoung /* Setmode not supported */
510 1.1 jdolecek mb86950_setmode(sc);
511 1.12 dyoung #endif
512 1.12 dyoung break;
513 1.12 dyoung case 0:
514 1.12 dyoung break;
515 1.1 jdolecek }
516 1.1 jdolecek
517 1.1 jdolecek #if ESTAR_DEBUG >= 1
518 1.1 jdolecek /* "ifconfig fe0 debug" to print register dump. */
519 1.1 jdolecek if (ifp->if_flags & IFF_DEBUG) {
520 1.1 jdolecek log(LOG_INFO, "%s: SIOCSIFFLAGS(DEBUG)\n",
521 1.11 cegger device_xname(&sc->sc_dev));
522 1.1 jdolecek mb86950_dump(LOG_DEBUG, sc);
523 1.1 jdolecek }
524 1.1 jdolecek #endif
525 1.1 jdolecek break;
526 1.1 jdolecek
527 1.1 jdolecek case SIOCGIFMEDIA:
528 1.1 jdolecek case SIOCSIFMEDIA:
529 1.1 jdolecek error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
530 1.1 jdolecek break;
531 1.1 jdolecek
532 1.1 jdolecek default:
533 1.12 dyoung error = ether_ioctl(ifp, cmd, data);
534 1.1 jdolecek break;
535 1.1 jdolecek }
536 1.1 jdolecek
537 1.1 jdolecek splx(s);
538 1.1 jdolecek return (error);
539 1.1 jdolecek }
540 1.1 jdolecek
541 1.1 jdolecek /*
542 1.1 jdolecek * Initialize device.
543 1.1 jdolecek */
544 1.1 jdolecek void
545 1.1 jdolecek mb86950_init(sc)
546 1.1 jdolecek struct mb86950_softc *sc;
547 1.1 jdolecek {
548 1.1 jdolecek bus_space_tag_t bst = sc->sc_bst;
549 1.1 jdolecek bus_space_handle_t bsh = sc->sc_bsh;
550 1.1 jdolecek struct ifnet *ifp = &sc->sc_ec.ec_if;
551 1.1 jdolecek
552 1.1 jdolecek /* Reset transmitter flags. */
553 1.1 jdolecek ifp->if_flags &= ~IFF_OACTIVE;
554 1.1 jdolecek ifp->if_timer = 0;
555 1.1 jdolecek sc->txb_sched = 0;
556 1.1 jdolecek
557 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_TX_MODE, LBC);
558 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_RX_MODE, NORMAL_MODE);
559 1.1 jdolecek
560 1.1 jdolecek /* Enable interrupts. */
561 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, TX_MASK);
562 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_RX_INT_EN, RX_MASK);
563 1.1 jdolecek
564 1.1 jdolecek /* Enable transmitter and receiver. */
565 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_CONFIG, ENABLE_DLC);
566 1.1 jdolecek delay(200);
567 1.1 jdolecek
568 1.1 jdolecek /* Set 'running' flag. */
569 1.1 jdolecek ifp->if_flags |= IFF_RUNNING;
570 1.1 jdolecek
571 1.1 jdolecek /* ...and attempt to start output. */
572 1.1 jdolecek mb86950_start(ifp);
573 1.1 jdolecek
574 1.1 jdolecek }
575 1.1 jdolecek
576 1.1 jdolecek void
577 1.1 jdolecek mb86950_start(ifp)
578 1.1 jdolecek struct ifnet *ifp;
579 1.1 jdolecek {
580 1.1 jdolecek struct mb86950_softc *sc = ifp->if_softc;
581 1.1 jdolecek bus_space_tag_t bst = sc->sc_bst;
582 1.1 jdolecek bus_space_handle_t bsh = sc->sc_bsh;
583 1.1 jdolecek struct mbuf *m;
584 1.1 jdolecek int len;
585 1.1 jdolecek
586 1.1 jdolecek if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
587 1.1 jdolecek return;
588 1.1 jdolecek
589 1.1 jdolecek IF_DEQUEUE(&ifp->if_snd, m);
590 1.1 jdolecek if (m == 0)
591 1.1 jdolecek return;
592 1.1 jdolecek
593 1.1 jdolecek #if NBPFILTER > 0
594 1.1 jdolecek /* Tap off here if there is a BPF listener. */
595 1.1 jdolecek if (ifp->if_bpf)
596 1.1 jdolecek bpf_mtap(ifp->if_bpf, m);
597 1.1 jdolecek #endif
598 1.1 jdolecek
599 1.2 jdolecek /* Send the packet to the mb86950 */
600 1.1 jdolecek len = mb86950_put_fifo(sc,m);
601 1.1 jdolecek m_freem(m);
602 1.1 jdolecek
603 1.2 jdolecek /* XXX bus_space_barrier here ? */
604 1.1 jdolecek if (bus_space_read_1(bst, bsh, DLCR_TX_STAT) & (TX_UNDERFLO | TX_BUS_WR_ERR)) {
605 1.11 cegger log(LOG_ERR, "%s: tx fifo underflow/overflow\n", device_xname(&sc->sc_dev));
606 1.1 jdolecek }
607 1.1 jdolecek
608 1.1 jdolecek bus_space_write_2(bst, bsh, BMPR_TX_LENGTH, len | TRANSMIT_START);
609 1.1 jdolecek
610 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, TX_MASK);
611 1.2 jdolecek /* XXX */
612 1.1 jdolecek sc->txb_sched++;
613 1.1 jdolecek
614 1.1 jdolecek /* We have space for 'n' transmit packets of size 'mtu. */
615 1.1 jdolecek if (sc->txb_sched > sc->txb_num_pkt) {
616 1.1 jdolecek ifp->if_flags |= IFF_OACTIVE;
617 1.1 jdolecek ifp->if_timer = 2;
618 1.1 jdolecek }
619 1.1 jdolecek }
620 1.1 jdolecek
621 1.1 jdolecek /*
622 1.2 jdolecek * Send packet - copy packet from mbuf to the fifo
623 1.1 jdolecek */
624 1.1 jdolecek u_short
625 1.1 jdolecek mb86950_put_fifo(sc, m)
626 1.1 jdolecek struct mb86950_softc *sc;
627 1.1 jdolecek struct mbuf *m;
628 1.1 jdolecek {
629 1.1 jdolecek bus_space_tag_t bst = sc->sc_bst;
630 1.1 jdolecek bus_space_handle_t bsh = sc->sc_bsh;
631 1.1 jdolecek u_short *data;
632 1.1 jdolecek u_char savebyte[2];
633 1.1 jdolecek int len, len1, wantbyte;
634 1.1 jdolecek u_short totlen;
635 1.1 jdolecek
636 1.5 mrg memset(savebyte, 0, sizeof(savebyte)); /* XXX gcc */
637 1.5 mrg
638 1.1 jdolecek totlen = wantbyte = 0;
639 1.1 jdolecek
640 1.1 jdolecek for (; m != NULL; m = m->m_next) {
641 1.1 jdolecek data = mtod(m, u_short *);
642 1.1 jdolecek len = m->m_len;
643 1.1 jdolecek if (len > 0) {
644 1.1 jdolecek totlen += len;
645 1.1 jdolecek
646 1.1 jdolecek /* Finish the last word. */
647 1.1 jdolecek if (wantbyte) {
648 1.1 jdolecek savebyte[1] = *((u_char *)data);
649 1.1 jdolecek bus_space_write_2(bst, bsh, BMPR_FIFO, *savebyte);
650 1.4 skrll data = (u_short *)((u_char *)data + 1);
651 1.1 jdolecek len--;
652 1.1 jdolecek wantbyte = 0;
653 1.1 jdolecek }
654 1.1 jdolecek /* Output contiguous words. */
655 1.1 jdolecek if (len > 1) {
656 1.1 jdolecek len1 = len/2;
657 1.1 jdolecek bus_space_write_multi_stream_2(bst, bsh, BMPR_FIFO, data, len1);
658 1.1 jdolecek data += len1;
659 1.1 jdolecek len &= 1;
660 1.1 jdolecek }
661 1.1 jdolecek /* Save last byte, if necessary. */
662 1.1 jdolecek if (len == 1) {
663 1.1 jdolecek savebyte[0] = *((u_char *)data);
664 1.1 jdolecek wantbyte = 1;
665 1.1 jdolecek }
666 1.1 jdolecek }
667 1.1 jdolecek }
668 1.1 jdolecek
669 1.1 jdolecek if (wantbyte) {
670 1.1 jdolecek savebyte[1] = 0;
671 1.1 jdolecek bus_space_write_2(bst, bsh, BMPR_FIFO, *savebyte);
672 1.1 jdolecek }
673 1.1 jdolecek
674 1.1 jdolecek if (totlen < (ETHER_MIN_LEN - ETHER_CRC_LEN)) {
675 1.1 jdolecek
676 1.1 jdolecek /* Fill the rest of the packet with zeros. */
677 1.2 jdolecek /* XXX Replace this mess with something else, eats CPU */
678 1.2 jdolecek /* The zero fill and last byte ought to be combined somehow */
679 1.1 jdolecek for(len = totlen + 1; len < (ETHER_MIN_LEN - ETHER_CRC_LEN); len += 2)
680 1.1 jdolecek bus_space_write_2(bst, bsh, BMPR_FIFO, 0);
681 1.2 jdolecek /* XXX */
682 1.1 jdolecek
683 1.1 jdolecek totlen = (ETHER_MIN_LEN - ETHER_CRC_LEN);
684 1.1 jdolecek }
685 1.1 jdolecek
686 1.1 jdolecek return (totlen);
687 1.1 jdolecek }
688 1.1 jdolecek
689 1.1 jdolecek /*
690 1.2 jdolecek * Handle interrupts.
691 1.1 jdolecek * Ethernet interface interrupt processor
692 1.1 jdolecek */
693 1.1 jdolecek int
694 1.1 jdolecek mb86950_intr(arg)
695 1.1 jdolecek void *arg;
696 1.1 jdolecek {
697 1.1 jdolecek struct mb86950_softc *sc = arg;
698 1.1 jdolecek bus_space_tag_t bst = sc->sc_bst;
699 1.1 jdolecek bus_space_handle_t bsh = sc->sc_bsh;
700 1.1 jdolecek struct ifnet *ifp = &sc->sc_ec.ec_if;
701 1.1 jdolecek u_int8_t tstat, rstat;
702 1.1 jdolecek
703 1.1 jdolecek /* Get interrupt status. */
704 1.1 jdolecek tstat = bus_space_read_1(bst, bsh, DLCR_TX_STAT);
705 1.1 jdolecek rstat = bus_space_read_1(bst, bsh, DLCR_RX_STAT);
706 1.1 jdolecek
707 1.1 jdolecek if (tstat == 0 && rstat == 0) return (0);
708 1.1 jdolecek
709 1.1 jdolecek /* Disable etherstar interrupts so that we won't miss anything. */
710 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, 0);
711 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_RX_INT_EN, 0);
712 1.1 jdolecek
713 1.1 jdolecek /*
714 1.1 jdolecek * Handle transmitter interrupts. Handle these first because
715 1.1 jdolecek * the receiver will reset the board under some conditions.
716 1.1 jdolecek */
717 1.1 jdolecek if (tstat != 0) {
718 1.1 jdolecek
719 1.1 jdolecek mb86950_tint(sc, tstat);
720 1.1 jdolecek
721 1.1 jdolecek /* acknowledge transmit interrupt status. */
722 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_TX_STAT, tstat);
723 1.1 jdolecek
724 1.1 jdolecek }
725 1.1 jdolecek
726 1.1 jdolecek /* Handle receiver interrupts. */
727 1.1 jdolecek if (rstat != 0) {
728 1.1 jdolecek
729 1.1 jdolecek mb86950_rint(sc, rstat);
730 1.1 jdolecek
731 1.1 jdolecek /* acknowledge receive interrupt status. */
732 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_RX_STAT, rstat);
733 1.1 jdolecek
734 1.1 jdolecek }
735 1.1 jdolecek
736 1.1 jdolecek /* If tx still pending reset tx interrupt mask */
737 1.2 jdolecek if (sc->txb_sched > 0)
738 1.2 jdolecek bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, TX_MASK);
739 1.1 jdolecek
740 1.1 jdolecek /*
741 1.1 jdolecek * If it looks like the transmitter can take more data,
742 1.1 jdolecek * attempt to start output on the interface. This is done
743 1.1 jdolecek * after handling the receiver interrupt to give the
744 1.1 jdolecek * receive operation priority.
745 1.1 jdolecek */
746 1.1 jdolecek
747 1.1 jdolecek if ((ifp->if_flags & IFF_OACTIVE) == 0)
748 1.1 jdolecek mb86950_start(ifp);
749 1.1 jdolecek
750 1.1 jdolecek /* Set receive interrupts back */
751 1.1 jdolecek bus_space_write_1(bst, bsh, DLCR_RX_INT_EN, RX_MASK);
752 1.1 jdolecek
753 1.1 jdolecek return(1);
754 1.1 jdolecek }
755 1.1 jdolecek
756 1.1 jdolecek /* Transmission interrupt handler */
757 1.1 jdolecek void
758 1.1 jdolecek mb86950_tint(sc, tstat)
759 1.1 jdolecek struct mb86950_softc *sc;
760 1.1 jdolecek u_int8_t tstat;
761 1.1 jdolecek {
762 1.1 jdolecek bus_space_tag_t bst = sc->sc_bst;
763 1.1 jdolecek bus_space_handle_t bsh = sc->sc_bsh;
764 1.1 jdolecek struct ifnet *ifp = &sc->sc_ec.ec_if;
765 1.1 jdolecek int col;
766 1.1 jdolecek
767 1.1 jdolecek if (tstat & (TX_UNDERFLO | TX_BUS_WR_ERR)) {
768 1.1 jdolecek /* XXX What do we need to do here? reset ? */
769 1.1 jdolecek ifp->if_oerrors++;
770 1.1 jdolecek }
771 1.1 jdolecek
772 1.1 jdolecek /* excessive collision */
773 1.1 jdolecek if (tstat & TX_16COL) {
774 1.1 jdolecek ifp->if_collisions += 16;
775 1.1 jdolecek /* 16 collisions means that the packet has been thrown away. */
776 1.2 jdolecek if (sc->txb_sched > 0)
777 1.2 jdolecek sc->txb_sched--;
778 1.1 jdolecek }
779 1.1 jdolecek
780 1.1 jdolecek /* transmission complete. */
781 1.1 jdolecek if (tstat & TX_DONE) {
782 1.1 jdolecek /* successfully transmitted packets ++. */
783 1.1 jdolecek ifp->if_opackets++;
784 1.2 jdolecek if (sc->txb_sched > 0)
785 1.2 jdolecek sc->txb_sched--;
786 1.1 jdolecek
787 1.1 jdolecek /* Collision count valid only when TX_DONE is set */
788 1.1 jdolecek if (tstat & TX_COL) {
789 1.1 jdolecek col = (bus_space_read_1(bst, bsh, DLCR_TX_MODE) & COL_MASK) >> 4;
790 1.1 jdolecek ifp->if_collisions = ifp->if_collisions + col;
791 1.1 jdolecek }
792 1.1 jdolecek }
793 1.1 jdolecek
794 1.1 jdolecek if (sc->txb_sched == 0) {
795 1.1 jdolecek /* Reset output active flag and stop timer. */
796 1.1 jdolecek ifp->if_flags &= ~IFF_OACTIVE;
797 1.1 jdolecek ifp->if_timer = 0;
798 1.1 jdolecek }
799 1.1 jdolecek }
800 1.1 jdolecek
801 1.1 jdolecek /* receiver interrupt. */
802 1.1 jdolecek void
803 1.1 jdolecek mb86950_rint(sc, rstat)
804 1.1 jdolecek struct mb86950_softc *sc;
805 1.1 jdolecek u_int8_t rstat;
806 1.1 jdolecek {
807 1.1 jdolecek bus_space_tag_t bst = sc->sc_bst;
808 1.1 jdolecek bus_space_handle_t bsh = sc->sc_bsh;
809 1.1 jdolecek struct ifnet *ifp = &sc->sc_ec.ec_if;
810 1.1 jdolecek u_int status, len;
811 1.1 jdolecek int i;
812 1.1 jdolecek
813 1.1 jdolecek /* Update statistics if this interrupt is caused by an error. */
814 1.1 jdolecek if (rstat & RX_ERR_MASK) {
815 1.1 jdolecek
816 1.1 jdolecek /* tried to read past end of fifo, should be harmless
817 1.1 jdolecek * count everything else
818 1.1 jdolecek */
819 1.1 jdolecek if ((rstat & RX_BUS_RD_ERR) == 0) {
820 1.1 jdolecek ifp->if_ierrors++;
821 1.1 jdolecek }
822 1.1 jdolecek }
823 1.1 jdolecek
824 1.1 jdolecek /*
825 1.1 jdolecek * mb86950 has a flag indicating "receive buffer empty."
826 1.1 jdolecek * We just loop checking the flag to pull out all received
827 1.1 jdolecek * packets.
828 1.1 jdolecek *
829 1.1 jdolecek * We limit the number of iterrations to avoid infinite loop.
830 1.1 jdolecek * It can be caused by a very slow CPU (some broken
831 1.1 jdolecek * peripheral may insert incredible number of wait cycles)
832 1.1 jdolecek * or, worse, by a broken mb86950 chip.
833 1.1 jdolecek */
834 1.1 jdolecek for (i = 0; i < sc->rxb_num_pkt; i++) {
835 1.1 jdolecek /* Stop the iterration if 86950 indicates no packets. */
836 1.1 jdolecek if (bus_space_read_1(bst, bsh, DLCR_RX_MODE) & RX_BUF_EMTY)
837 1.1 jdolecek break;
838 1.1 jdolecek
839 1.1 jdolecek /* receive packet status */
840 1.1 jdolecek status = bus_space_read_2(bst, bsh, BMPR_FIFO);
841 1.1 jdolecek
842 1.1 jdolecek /* bad packet? */
843 1.1 jdolecek if ((status & GOOD_PKT) == 0) {
844 1.1 jdolecek ifp->if_ierrors++;
845 1.1 jdolecek mb86950_drain_fifo(sc);
846 1.1 jdolecek continue;
847 1.1 jdolecek }
848 1.1 jdolecek
849 1.1 jdolecek /* Length valid ? */
850 1.1 jdolecek len = bus_space_read_2(bst, bsh, BMPR_FIFO);
851 1.1 jdolecek
852 1.1 jdolecek if (len > (ETHER_MAX_LEN - ETHER_CRC_LEN) || len < ETHER_HDR_LEN) {
853 1.1 jdolecek ifp->if_ierrors++;
854 1.1 jdolecek mb86950_drain_fifo(sc);
855 1.1 jdolecek continue;
856 1.1 jdolecek }
857 1.1 jdolecek
858 1.1 jdolecek if (mb86950_get_fifo(sc, len) != 0) {
859 1.1 jdolecek /* No mbufs? Drop packet. */
860 1.1 jdolecek ifp->if_ierrors++;
861 1.1 jdolecek mb86950_drain_fifo(sc);
862 1.1 jdolecek return;
863 1.1 jdolecek }
864 1.1 jdolecek
865 1.1 jdolecek /* Successfully received a packet. Update stat. */
866 1.1 jdolecek ifp->if_ipackets++;
867 1.1 jdolecek }
868 1.1 jdolecek }
869 1.1 jdolecek
870 1.1 jdolecek /*
871 1.2 jdolecek * Receive packet.
872 1.1 jdolecek * Retrieve packet from receive buffer and send to the next level up via
873 1.1 jdolecek * ether_input(). If there is a BPF listener, give a copy to BPF, too.
874 1.1 jdolecek * Returns 0 if success, -1 if error (i.e., mbuf allocation failure).
875 1.1 jdolecek */
876 1.1 jdolecek int
877 1.1 jdolecek mb86950_get_fifo(sc, len)
878 1.1 jdolecek struct mb86950_softc *sc;
879 1.1 jdolecek u_int len;
880 1.1 jdolecek {
881 1.1 jdolecek bus_space_tag_t bst = sc->sc_bst;
882 1.1 jdolecek bus_space_handle_t bsh = sc->sc_bsh;
883 1.1 jdolecek struct ifnet *ifp = &sc->sc_ec.ec_if;
884 1.1 jdolecek struct mbuf *m;
885 1.1 jdolecek
886 1.1 jdolecek /* Allocate a header mbuf. */
887 1.1 jdolecek MGETHDR(m, M_DONTWAIT, MT_DATA);
888 1.1 jdolecek if (m == 0)
889 1.1 jdolecek return (-1);
890 1.1 jdolecek
891 1.1 jdolecek /*
892 1.1 jdolecek * Round len to even value.
893 1.1 jdolecek */
894 1.1 jdolecek if (len & 1)
895 1.1 jdolecek len++;
896 1.1 jdolecek
897 1.1 jdolecek m->m_pkthdr.rcvif = ifp;
898 1.1 jdolecek m->m_pkthdr.len = len;
899 1.1 jdolecek
900 1.1 jdolecek /* The following silliness is to make NFS happy. */
901 1.1 jdolecek #define EROUND ((sizeof(struct ether_header) + 3) & ~3)
902 1.1 jdolecek #define EOFF (EROUND - sizeof(struct ether_header))
903 1.1 jdolecek
904 1.1 jdolecek /*
905 1.1 jdolecek * Our strategy has one more problem. There is a policy on
906 1.1 jdolecek * mbuf cluster allocation. It says that we must have at
907 1.1 jdolecek * least MINCLSIZE (208 bytes) to allocate a cluster. For a
908 1.1 jdolecek * packet of a size between (MHLEN - 2) to (MINCLSIZE - 2),
909 1.1 jdolecek * our code violates the rule...
910 1.1 jdolecek * On the other hand, the current code is short, simple,
911 1.1 jdolecek * and fast, however. It does no harmful thing, just wastes
912 1.1 jdolecek * some memory. Any comments? FIXME.
913 1.1 jdolecek */
914 1.1 jdolecek
915 1.1 jdolecek /* Attach a cluster if this packet doesn't fit in a normal mbuf. */
916 1.1 jdolecek if (len > MHLEN - EOFF) {
917 1.1 jdolecek MCLGET(m, M_DONTWAIT);
918 1.1 jdolecek if ((m->m_flags & M_EXT) == 0) {
919 1.1 jdolecek m_freem(m);
920 1.1 jdolecek return (-1);
921 1.1 jdolecek }
922 1.1 jdolecek }
923 1.1 jdolecek
924 1.1 jdolecek /*
925 1.1 jdolecek * The following assumes there is room for the ether header in the
926 1.1 jdolecek * header mbuf.
927 1.1 jdolecek */
928 1.1 jdolecek m->m_data += EOFF;
929 1.1 jdolecek
930 1.1 jdolecek /* Set the length of this packet. */
931 1.1 jdolecek m->m_len = len;
932 1.1 jdolecek
933 1.1 jdolecek /* Get a packet. */
934 1.1 jdolecek bus_space_read_multi_stream_2(bst, bsh, BMPR_FIFO, mtod(m, u_int16_t *), (len + 1) >> 1);
935 1.1 jdolecek
936 1.1 jdolecek #if NBPFILTER > 0
937 1.1 jdolecek /*
938 1.1 jdolecek * Check if there's a BPF listener on this interface. If so, hand off
939 1.1 jdolecek * the raw packet to bpf.
940 1.1 jdolecek */
941 1.1 jdolecek if (ifp->if_bpf)
942 1.1 jdolecek bpf_mtap(ifp->if_bpf, m);
943 1.1 jdolecek #endif
944 1.1 jdolecek
945 1.1 jdolecek (*ifp->if_input)(ifp, m);
946 1.1 jdolecek return (0);
947 1.1 jdolecek }
948 1.1 jdolecek
949 1.1 jdolecek /*
950 1.1 jdolecek * Enable power on the interface.
951 1.1 jdolecek */
952 1.1 jdolecek int
953 1.1 jdolecek mb86950_enable(sc)
954 1.1 jdolecek struct mb86950_softc *sc;
955 1.1 jdolecek {
956 1.1 jdolecek
957 1.1 jdolecek if ((sc->sc_stat & ESTAR_STAT_ENABLED) == 0 && sc->sc_enable != NULL) {
958 1.1 jdolecek if ((*sc->sc_enable)(sc) != 0) {
959 1.11 cegger aprint_error_dev(&sc->sc_dev, "device enable failed\n");
960 1.1 jdolecek return (EIO);
961 1.1 jdolecek }
962 1.1 jdolecek }
963 1.1 jdolecek
964 1.1 jdolecek sc->sc_stat |= ESTAR_STAT_ENABLED;
965 1.1 jdolecek return (0);
966 1.1 jdolecek }
967 1.1 jdolecek
968 1.1 jdolecek /*
969 1.1 jdolecek * Disable power on the interface.
970 1.1 jdolecek */
971 1.1 jdolecek void
972 1.1 jdolecek mb86950_disable(sc)
973 1.1 jdolecek struct mb86950_softc *sc;
974 1.1 jdolecek {
975 1.1 jdolecek
976 1.1 jdolecek if ((sc->sc_stat & ESTAR_STAT_ENABLED) != 0 && sc->sc_disable != NULL) {
977 1.1 jdolecek (*sc->sc_disable)(sc);
978 1.1 jdolecek sc->sc_stat &= ~ESTAR_STAT_ENABLED;
979 1.1 jdolecek }
980 1.1 jdolecek }
981 1.1 jdolecek
982 1.1 jdolecek /*
983 1.1 jdolecek * mbe_activate:
984 1.1 jdolecek *
985 1.1 jdolecek * Handle device activation/deactivation requests.
986 1.1 jdolecek */
987 1.1 jdolecek int
988 1.1 jdolecek mb86950_activate(self, act)
989 1.1 jdolecek struct device *self;
990 1.1 jdolecek enum devact act;
991 1.1 jdolecek {
992 1.1 jdolecek struct mb86950_softc *sc = (struct mb86950_softc *)self;
993 1.1 jdolecek int rv, s;
994 1.1 jdolecek
995 1.1 jdolecek rv = 0;
996 1.1 jdolecek s = splnet();
997 1.1 jdolecek switch (act) {
998 1.1 jdolecek case DVACT_ACTIVATE:
999 1.1 jdolecek rv = EOPNOTSUPP;
1000 1.1 jdolecek break;
1001 1.1 jdolecek
1002 1.1 jdolecek case DVACT_DEACTIVATE:
1003 1.1 jdolecek if_deactivate(&sc->sc_ec.ec_if);
1004 1.1 jdolecek break;
1005 1.1 jdolecek }
1006 1.1 jdolecek splx(s);
1007 1.1 jdolecek return (rv);
1008 1.1 jdolecek }
1009 1.1 jdolecek
1010 1.1 jdolecek /*
1011 1.1 jdolecek * mb86950_detach:
1012 1.1 jdolecek *
1013 1.1 jdolecek * Detach a mb86950 interface.
1014 1.1 jdolecek */
1015 1.1 jdolecek int
1016 1.1 jdolecek mb86950_detach(sc)
1017 1.1 jdolecek struct mb86950_softc *sc;
1018 1.1 jdolecek {
1019 1.1 jdolecek struct ifnet *ifp = &sc->sc_ec.ec_if;
1020 1.1 jdolecek
1021 1.1 jdolecek /* Succeed now if there's no work to do. */
1022 1.1 jdolecek if ((sc->sc_stat & ESTAR_STAT_ATTACHED) == 0)
1023 1.1 jdolecek return (0);
1024 1.1 jdolecek
1025 1.1 jdolecek /* Delete all media. */
1026 1.1 jdolecek ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
1027 1.1 jdolecek
1028 1.1 jdolecek #if NRND > 0
1029 1.1 jdolecek /* Unhook the entropy source. */
1030 1.1 jdolecek rnd_detach_source(&sc->rnd_source);
1031 1.1 jdolecek #endif
1032 1.1 jdolecek ether_ifdetach(ifp);
1033 1.1 jdolecek if_detach(ifp);
1034 1.1 jdolecek
1035 1.1 jdolecek return (0);
1036 1.1 jdolecek }
1037 1.1 jdolecek
1038 1.1 jdolecek #if ESTAR_DEBUG >= 1
1039 1.1 jdolecek void
1040 1.1 jdolecek mb86950_dump(level, sc)
1041 1.1 jdolecek int level;
1042 1.1 jdolecek struct mb86950_softc *sc;
1043 1.1 jdolecek {
1044 1.1 jdolecek bus_space_tag_t bst = sc->sc_bst;
1045 1.1 jdolecek bus_space_handle_t bsh = sc->sc_bsh;
1046 1.1 jdolecek
1047 1.1 jdolecek log(level, "\tDLCR = %02x %02x %02x %02x %02x %02x %02x\n",
1048 1.1 jdolecek bus_space_read_1(bst, bsh, DLCR_TX_STAT),
1049 1.1 jdolecek bus_space_read_1(bst, bsh, DLCR_TX_INT_EN),
1050 1.1 jdolecek bus_space_read_1(bst, bsh, DLCR_RX_STAT),
1051 1.1 jdolecek bus_space_read_1(bst, bsh, DLCR_RX_INT_EN),
1052 1.1 jdolecek bus_space_read_1(bst, bsh, DLCR_TX_MODE),
1053 1.1 jdolecek bus_space_read_1(bst, bsh, DLCR_RX_MODE),
1054 1.1 jdolecek bus_space_read_1(bst, bsh, DLCR_CONFIG));
1055 1.1 jdolecek
1056 1.2 jdolecek /* XXX BMPR2, 4 write only ?
1057 1.1 jdolecek log(level, "\tBMPR = xxxx %04x %04x\n",
1058 1.1 jdolecek bus_space_read_2(bst, bsh, BMPR_TX_LENGTH),
1059 1.1 jdolecek bus_space_read_2(bst, bsh, BMPR_DMA));
1060 1.2 jdolecek */
1061 1.1 jdolecek }
1062 1.1 jdolecek #endif
1063