Commit | Line | Data |
---|---|---|
984263bc | 1 | /* $NetBSD: if_de.c,v 1.86 1999/06/01 19:17:59 thorpej Exp $ */ |
984263bc MD |
2 | /*- |
3 | * Copyright (c) 1994-1997 Matt Thomas (matt@3am-software.com) | |
4 | * All rights reserved. | |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * 2. The name of the author may not be used to endorse or promote products | |
4d9022e3 | 12 | * derived from this software without specific prior written permission |
984263bc MD |
13 | * |
14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
16 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
17 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
18 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
19 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
20 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
21 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
23 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
24 | * | |
25 | * Id: if_de.c,v 1.94 1997/07/03 16:55:07 thomas Exp | |
984263bc MD |
26 | */ |
27 | ||
28 | /* | |
29 | * DEC 21040 PCI Ethernet Controller | |
30 | * | |
31 | * Written by Matt Thomas | |
32 | * BPF support code stolen directly from if_ec.c | |
33 | * | |
34 | * This driver supports the DEC DE435 or any other PCI | |
35 | * board which support 21040, 21041, or 21140 (mostly). | |
36 | */ | |
984263bc | 37 | |
5d2944c2 IV |
38 | #include <sys/cdefs.h> |
39 | __FBSDID("$FreeBSD: head/sys/dev/de/if_de.c 271849 2014-09-19 03:51:26Z glebius $"); | |
40 | ||
984263bc MD |
41 | #include <sys/param.h> |
42 | #include <sys/systm.h> | |
5d2944c2 | 43 | #include <sys/endian.h> |
984263bc MD |
44 | #include <sys/mbuf.h> |
45 | #include <sys/socket.h> | |
46 | #include <sys/sockio.h> | |
47 | #include <sys/malloc.h> | |
48 | #include <sys/kernel.h> | |
49 | #include <sys/eventhandler.h> | |
984263bc MD |
50 | #include <sys/bus.h> |
51 | #include <sys/rman.h> | |
9db4b353 | 52 | #include <sys/interrupt.h> |
984263bc MD |
53 | |
54 | #include "opt_inet.h" | |
984263bc MD |
55 | |
56 | #include <net/if.h> | |
57 | #include <net/if_media.h> | |
58 | #include <net/if_dl.h> | |
9db4b353 | 59 | #include <net/ifq_var.h> |
984263bc MD |
60 | #include <net/bpf.h> |
61 | ||
62 | #ifdef INET | |
63 | #include <netinet/in.h> | |
64 | #include <netinet/if_ether.h> | |
65 | #endif | |
66 | ||
984263bc MD |
67 | #include <vm/vm.h> |
68 | ||
69 | #include <net/if_var.h> | |
70 | #include <vm/pmap.h> | |
1f2de5d4 MD |
71 | #include <bus/pci/pcivar.h> |
72 | #include <bus/pci/pcireg.h> | |
04819c3b | 73 | #include <dev/netif/de/dc21040reg.h> |
984263bc MD |
74 | |
75 | /* | |
76 | * Intel CPUs should use I/O mapped access. | |
77 | */ | |
c9542bdb | 78 | #if defined(__x86_64__) |
984263bc MD |
79 | #define TULIP_IOMAPPED |
80 | #endif | |
81 | ||
984263bc MD |
82 | #define TULIP_HZ 10 |
83 | ||
1f2de5d4 | 84 | #include "if_devar.h" |
984263bc | 85 | |
5d2944c2 IV |
86 | #define SYNC_NONE 0 |
87 | #define SYNC_RX 1 | |
88 | #define SYNC_TX 2 | |
89 | ||
cdfcdfb0 JS |
90 | static tulip_softc_t *tulips[TULIP_MAX_DEVICES]; |
91 | ||
984263bc MD |
92 | /* |
93 | * This module supports | |
94 | * the DEC 21040 PCI Ethernet Controller. | |
95 | * the DEC 21041 PCI Ethernet Controller. | |
96 | * the DEC 21140 PCI Fast Ethernet Controller. | |
97 | */ | |
79fe23de JS |
98 | static void tulip_mii_autonegotiate(tulip_softc_t *, u_int); |
99 | static void tulip_intr_shared(void *); | |
100 | static void tulip_intr_normal(void *); | |
101 | static void tulip_init(tulip_softc_t *); | |
102 | static void tulip_reset(tulip_softc_t *); | |
f0a26983 | 103 | static void tulip_ifstart(struct ifnet *, struct ifaltq_subque *); |
79fe23de JS |
104 | static struct mbuf *tulip_txput(tulip_softc_t *, struct mbuf *); |
105 | static void tulip_txput_setup(tulip_softc_t *); | |
106 | static void tulip_rx_intr(tulip_softc_t *); | |
107 | static void tulip_addr_filter(tulip_softc_t *); | |
108 | static u_int tulip_mii_readreg(tulip_softc_t *, u_int, u_int); | |
109 | static void tulip_mii_writereg(tulip_softc_t *, u_int, u_int, u_int); | |
110 | static int tulip_mii_map_abilities(tulip_softc_t * const sc, unsigned abilities); | |
111 | static tulip_media_t tulip_mii_phy_readspecific(tulip_softc_t *); | |
112 | static int tulip_srom_decode(tulip_softc_t *); | |
113 | static int tulip_ifmedia_change(struct ifnet *); | |
114 | static void tulip_ifmedia_status(struct ifnet *, struct ifmediareq *); | |
5d2944c2 IV |
115 | static struct mbuf *tulip_dequeue_mbuf(tulip_ringinfo_t *ri, tulip_descinfo_t *di, |
116 | int sync); | |
117 | static void tulip_dma_map_addr(void *, bus_dma_segment_t *, int, int); | |
118 | static void tulip_dma_map_rxbuf(void *, bus_dma_segment_t *, int, | |
119 | bus_size_t, int); | |
a5898a47 | 120 | static void tulip_ifinit(void *); |
5d2944c2 IV |
121 | |
122 | static void | |
123 | tulip_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) | |
124 | { | |
125 | bus_addr_t *paddr; | |
126 | ||
127 | if (error) | |
128 | return; | |
129 | ||
130 | paddr = arg; | |
131 | *paddr = segs->ds_addr; | |
132 | } | |
133 | ||
134 | static void | |
135 | tulip_dma_map_rxbuf(void *arg, bus_dma_segment_t *segs, int nseg, | |
136 | bus_size_t mapsize, int error) | |
137 | { | |
138 | tulip_desc_t *desc; | |
139 | ||
140 | if (error) | |
141 | return; | |
142 | ||
143 | desc = arg; | |
144 | KASSERT(nseg == 1, ("too many DMA segments")); | |
145 | KASSERT(segs[0].ds_len >= TULIP_RX_BUFLEN, ("receive buffer too small")); | |
146 | ||
147 | desc->d_addr1 = segs[0].ds_addr & 0xffffffff; | |
148 | desc->d_length1 = TULIP_RX_BUFLEN; | |
149 | #ifdef not_needed | |
150 | /* These should already always be zero. */ | |
151 | desc->d_addr2 = 0; | |
152 | desc->d_length2 = 0; | |
153 | #endif | |
154 | } | |
155 | ||
156 | static struct mbuf * | |
157 | tulip_dequeue_mbuf(tulip_ringinfo_t *ri, tulip_descinfo_t *di, int sync) | |
158 | { | |
159 | struct mbuf *m; | |
160 | ||
161 | m = di->di_mbuf; | |
162 | if (m != NULL) { | |
163 | switch (sync) { | |
164 | case SYNC_NONE: | |
165 | break; | |
166 | case SYNC_RX: | |
167 | TULIP_RXMAP_POSTSYNC(ri, di); | |
168 | break; | |
169 | case SYNC_TX: | |
170 | TULIP_TXMAP_POSTSYNC(ri, di); | |
171 | break; | |
172 | default: | |
173 | panic("bad sync flag: %d", sync); | |
174 | } | |
175 | bus_dmamap_unload(ri->ri_data_tag, *di->di_map); | |
176 | di->di_mbuf = NULL; | |
177 | } | |
178 | return (m); | |
179 | } | |
79fe23de | 180 | |
984263bc | 181 | static void |
79fe23de | 182 | tulip_timeout_callback(void *arg) |
984263bc | 183 | { |
79fe23de | 184 | tulip_softc_t *sc = arg; |
61b0028a | 185 | |
5d2944c2 | 186 | lwkt_serialize_enter(sc->arpcom.ac_if.if_serializer); |
984263bc MD |
187 | sc->tulip_flags &= ~TULIP_TIMEOUTPENDING; |
188 | sc->tulip_probe_timeout -= 1000 / TULIP_HZ; | |
189 | (sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_TIMER); | |
5d2944c2 | 190 | lwkt_serialize_exit(sc->arpcom.ac_if.if_serializer); |
984263bc MD |
191 | } |
192 | ||
193 | static void | |
79fe23de | 194 | tulip_timeout(tulip_softc_t *sc) |
984263bc MD |
195 | { |
196 | if (sc->tulip_flags & TULIP_TIMEOUTPENDING) | |
197 | return; | |
198 | sc->tulip_flags |= TULIP_TIMEOUTPENDING; | |
5d2944c2 IV |
199 | callout_reset(&sc->tulip_callout, (hz + TULIP_HZ / 2) / TULIP_HZ, |
200 | tulip_timeout_callback, sc); | |
984263bc MD |
201 | } |
202 | ||
984263bc | 203 | static int |
79fe23de | 204 | tulip_txprobe(tulip_softc_t *sc) |
984263bc MD |
205 | { |
206 | struct mbuf *m; | |
78195a76 | 207 | |
984263bc MD |
208 | /* |
209 | * Before we are sure this is the right media we need | |
210 | * to send a small packet to make sure there's carrier. | |
211 | * Strangely, BNC and AUI will "see" receive data if | |
212 | * either is connected so the transmit is the only way | |
213 | * to verify the connectivity. | |
214 | */ | |
b5523eac | 215 | MGETHDR(m, M_NOWAIT, MT_DATA); |
984263bc MD |
216 | if (m == NULL) |
217 | return 0; | |
218 | /* | |
219 | * Construct a LLC TEST message which will point to ourselves. | |
220 | */ | |
5d2944c2 IV |
221 | bcopy(sc->arpcom.ac_enaddr, mtod(m, struct ether_header *)->ether_dhost, |
222 | ETHER_ADDR_LEN); | |
223 | bcopy(sc->arpcom.ac_enaddr, mtod(m, struct ether_header *)->ether_shost, | |
224 | ETHER_ADDR_LEN); | |
984263bc MD |
225 | mtod(m, struct ether_header *)->ether_type = htons(3); |
226 | mtod(m, unsigned char *)[14] = 0; | |
227 | mtod(m, unsigned char *)[15] = 0; | |
228 | mtod(m, unsigned char *)[16] = 0xE3; /* LLC Class1 TEST (no poll) */ | |
229 | m->m_len = m->m_pkthdr.len = sizeof(struct ether_header) + 3; | |
230 | /* | |
231 | * send it! | |
232 | */ | |
233 | sc->tulip_cmdmode |= TULIP_CMD_TXRUN; | |
234 | sc->tulip_intrmask |= TULIP_STS_TXINTR; | |
235 | sc->tulip_flags |= TULIP_TXPROBE_ACTIVE; | |
236 | TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); | |
237 | TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); | |
238 | if ((m = tulip_txput(sc, m)) != NULL) | |
239 | m_freem(m); | |
240 | sc->tulip_probe.probe_txprobes++; | |
241 | return 1; | |
242 | } | |
79fe23de | 243 | |
984263bc | 244 | static void |
79fe23de | 245 | tulip_media_set(tulip_softc_t *sc, tulip_media_t media) |
984263bc MD |
246 | { |
247 | const tulip_media_info_t *mi = sc->tulip_mediums[media]; | |
248 | ||
249 | if (mi == NULL) | |
250 | return; | |
251 | ||
252 | /* | |
253 | * If we are switching media, make sure we don't think there's | |
254 | * any stale RX activity | |
255 | */ | |
256 | sc->tulip_flags &= ~TULIP_RXACT; | |
257 | if (mi->mi_type == TULIP_MEDIAINFO_SIA) { | |
258 | TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET); | |
259 | TULIP_CSR_WRITE(sc, csr_sia_tx_rx, mi->mi_sia_tx_rx); | |
260 | if (sc->tulip_features & TULIP_HAVE_SIAGP) { | |
5d2944c2 | 261 | TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_control|mi->mi_sia_general); |
984263bc | 262 | DELAY(50); |
5d2944c2 | 263 | TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_gp_data|mi->mi_sia_general); |
984263bc | 264 | } else { |
5d2944c2 | 265 | TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_sia_general); |
984263bc MD |
266 | } |
267 | TULIP_CSR_WRITE(sc, csr_sia_connectivity, mi->mi_sia_connectivity); | |
268 | } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) { | |
269 | #define TULIP_GPR_CMDBITS (TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_SCRAMBLER|TULIP_CMD_TXTHRSHLDCTL) | |
270 | /* | |
271 | * If the cmdmode bits don't match the currently operating mode, | |
272 | * set the cmdmode appropriately and reset the chip. | |
273 | */ | |
274 | if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { | |
275 | sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; | |
276 | sc->tulip_cmdmode |= mi->mi_cmdmode; | |
277 | tulip_reset(sc); | |
278 | } | |
279 | TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit); | |
280 | DELAY(10); | |
281 | TULIP_CSR_WRITE(sc, csr_gp, (u_int8_t) mi->mi_gpdata); | |
282 | } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) { | |
283 | /* | |
284 | * If the cmdmode bits don't match the currently operating mode, | |
285 | * set the cmdmode appropriately and reset the chip. | |
286 | */ | |
287 | if (((mi->mi_cmdmode ^ TULIP_CSR_READ(sc, csr_command)) & TULIP_GPR_CMDBITS) != 0) { | |
288 | sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; | |
289 | sc->tulip_cmdmode |= mi->mi_cmdmode; | |
290 | tulip_reset(sc); | |
291 | } | |
292 | TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpcontrol); | |
293 | TULIP_CSR_WRITE(sc, csr_sia_general, mi->mi_gpdata); | |
294 | } else if (mi->mi_type == TULIP_MEDIAINFO_MII | |
295 | && sc->tulip_probe_state != TULIP_PROBE_INACTIVE) { | |
296 | int idx; | |
297 | if (sc->tulip_features & TULIP_HAVE_SIAGP) { | |
298 | const u_int8_t *dp; | |
299 | dp = &sc->tulip_rombuf[mi->mi_reset_offset]; | |
300 | for (idx = 0; idx < mi->mi_reset_length; idx++, dp += 2) { | |
301 | DELAY(10); | |
302 | TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); | |
303 | } | |
304 | sc->tulip_phyaddr = mi->mi_phyaddr; | |
305 | dp = &sc->tulip_rombuf[mi->mi_gpr_offset]; | |
306 | for (idx = 0; idx < mi->mi_gpr_length; idx++, dp += 2) { | |
307 | DELAY(10); | |
308 | TULIP_CSR_WRITE(sc, csr_sia_general, (dp[0] + 256 * dp[1]) << 16); | |
309 | } | |
310 | } else { | |
311 | for (idx = 0; idx < mi->mi_reset_length; idx++) { | |
312 | DELAY(10); | |
313 | TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx]); | |
314 | } | |
315 | sc->tulip_phyaddr = mi->mi_phyaddr; | |
316 | for (idx = 0; idx < mi->mi_gpr_length; idx++) { | |
317 | DELAY(10); | |
318 | TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx]); | |
319 | } | |
320 | } | |
321 | if (sc->tulip_flags & TULIP_TRYNWAY) { | |
322 | tulip_mii_autonegotiate(sc, sc->tulip_phyaddr); | |
323 | } else if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { | |
324 | u_int32_t data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_CONTROL); | |
325 | data &= ~(PHYCTL_SELECT_100MB|PHYCTL_FULL_DUPLEX|PHYCTL_AUTONEG_ENABLE); | |
326 | sc->tulip_flags &= ~TULIP_DIDNWAY; | |
327 | if (TULIP_IS_MEDIA_FD(media)) | |
328 | data |= PHYCTL_FULL_DUPLEX; | |
329 | if (TULIP_IS_MEDIA_100MB(media)) | |
330 | data |= PHYCTL_SELECT_100MB; | |
331 | tulip_mii_writereg(sc, sc->tulip_phyaddr, PHYREG_CONTROL, data); | |
332 | } | |
333 | } | |
334 | } | |
79fe23de | 335 | |
984263bc | 336 | static void |
79fe23de | 337 | tulip_linkup(tulip_softc_t *sc, tulip_media_t media) |
984263bc MD |
338 | { |
339 | if ((sc->tulip_flags & TULIP_LINKUP) == 0) | |
340 | sc->tulip_flags |= TULIP_PRINTLINKUP; | |
341 | sc->tulip_flags |= TULIP_LINKUP; | |
5d2944c2 | 342 | ifq_clr_oactive(&sc->arpcom.ac_if.if_snd); |
984263bc MD |
343 | #if 0 /* XXX how does with work with ifmedia? */ |
344 | if ((sc->tulip_flags & TULIP_DIDNWAY) == 0) { | |
5d2944c2 | 345 | if (sc->arpcom.ac_if.if_flags & IFF_FULLDUPLEX) { |
984263bc MD |
346 | if (TULIP_CAN_MEDIA_FD(media) |
347 | && sc->tulip_mediums[TULIP_FD_MEDIA_OF(media)] != NULL) | |
348 | media = TULIP_FD_MEDIA_OF(media); | |
349 | } else { | |
350 | if (TULIP_IS_MEDIA_FD(media) | |
351 | && sc->tulip_mediums[TULIP_HD_MEDIA_OF(media)] != NULL) | |
352 | media = TULIP_HD_MEDIA_OF(media); | |
353 | } | |
354 | } | |
355 | #endif | |
356 | if (sc->tulip_media != media) { | |
984263bc MD |
357 | sc->tulip_media = media; |
358 | sc->tulip_flags |= TULIP_PRINTMEDIA; | |
359 | if (TULIP_IS_MEDIA_FD(sc->tulip_media)) { | |
360 | sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; | |
361 | } else if (sc->tulip_chipid != TULIP_21041 || (sc->tulip_flags & TULIP_DIDNWAY) == 0) { | |
362 | sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; | |
363 | } | |
364 | } | |
365 | /* | |
366 | * We could set probe_timeout to 0 but setting to 3000 puts this | |
367 | * in one central place and the only matters is tulip_link is | |
368 | * followed by a tulip_timeout. Therefore setting it should not | |
369 | * result in aberrant behavour. | |
370 | */ | |
371 | sc->tulip_probe_timeout = 3000; | |
372 | sc->tulip_probe_state = TULIP_PROBE_INACTIVE; | |
373 | sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_TRYNWAY); | |
374 | if (sc->tulip_flags & TULIP_INRESET) { | |
375 | tulip_media_set(sc, sc->tulip_media); | |
376 | } else if (sc->tulip_probe_media != sc->tulip_media) { | |
377 | /* | |
378 | * No reason to change media if we have the right media. | |
379 | */ | |
380 | tulip_reset(sc); | |
381 | } | |
382 | tulip_init(sc); | |
383 | } | |
79fe23de | 384 | |
984263bc | 385 | static void |
79fe23de | 386 | tulip_media_print(tulip_softc_t *sc) |
984263bc MD |
387 | { |
388 | if ((sc->tulip_flags & TULIP_LINKUP) == 0) | |
389 | return; | |
390 | if (sc->tulip_flags & TULIP_PRINTMEDIA) { | |
5d2944c2 IV |
391 | if_printf(&sc->arpcom.ac_if, "enabling %s port\n", |
392 | tulip_mediums[sc->tulip_media]); | |
984263bc MD |
393 | sc->tulip_flags &= ~(TULIP_PRINTMEDIA|TULIP_PRINTLINKUP); |
394 | } else if (sc->tulip_flags & TULIP_PRINTLINKUP) { | |
5d2944c2 | 395 | if_printf(&sc->arpcom.ac_if, "link up\n"); |
984263bc MD |
396 | sc->tulip_flags &= ~TULIP_PRINTLINKUP; |
397 | } | |
398 | } | |
79fe23de | 399 | |
984263bc | 400 | static tulip_link_status_t |
79fe23de | 401 | tulip_media_link_monitor(tulip_softc_t *sc) |
984263bc | 402 | { |
79fe23de | 403 | const tulip_media_info_t *mi = sc->tulip_mediums[sc->tulip_media]; |
984263bc MD |
404 | tulip_link_status_t linkup = TULIP_LINK_DOWN; |
405 | ||
406 | if (mi == NULL) { | |
46a77a85 | 407 | #if defined(DIAGNOSTIC) |
5d2944c2 | 408 | panic("tulip_media_link_monitor: %s: botch at line %d\n", |
984263bc MD |
409 | tulip_mediums[sc->tulip_media],__LINE__); |
410 | #endif | |
411 | return TULIP_LINK_UNKNOWN; | |
412 | } | |
413 | ||
414 | ||
415 | /* | |
416 | * Have we seen some packets? If so, the link must be good. | |
417 | */ | |
418 | if ((sc->tulip_flags & (TULIP_RXACT|TULIP_LINKUP)) == (TULIP_RXACT|TULIP_LINKUP)) { | |
419 | sc->tulip_flags &= ~TULIP_RXACT; | |
420 | sc->tulip_probe_timeout = 3000; | |
421 | return TULIP_LINK_UP; | |
422 | } | |
423 | ||
424 | sc->tulip_flags &= ~TULIP_RXACT; | |
425 | if (mi->mi_type == TULIP_MEDIAINFO_MII) { | |
426 | u_int32_t status; | |
427 | /* | |
428 | * Read the PHY status register. | |
429 | */ | |
430 | status = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS); | |
431 | if (status & PHYSTS_AUTONEG_DONE) { | |
432 | /* | |
433 | * If the PHY has completed autonegotiation, see the if the | |
434 | * remote systems abilities have changed. If so, upgrade or | |
435 | * downgrade as appropriate. | |
436 | */ | |
437 | u_int32_t abilities = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_AUTONEG_ABILITIES); | |
438 | abilities = (abilities << 6) & status; | |
439 | if (abilities != sc->tulip_abilities) { | |
984263bc MD |
440 | if (tulip_mii_map_abilities(sc, abilities)) { |
441 | tulip_linkup(sc, sc->tulip_probe_media); | |
442 | return TULIP_LINK_UP; | |
443 | } | |
444 | /* | |
445 | * if we had selected media because of autonegotiation, | |
446 | * we need to probe for the new media. | |
447 | */ | |
448 | sc->tulip_probe_state = TULIP_PROBE_INACTIVE; | |
449 | if (sc->tulip_flags & TULIP_DIDNWAY) | |
450 | return TULIP_LINK_DOWN; | |
451 | } | |
452 | } | |
453 | /* | |
454 | * The link is now up. If was down, say its back up. | |
455 | */ | |
456 | if ((status & (PHYSTS_LINK_UP|PHYSTS_REMOTE_FAULT)) == PHYSTS_LINK_UP) | |
457 | linkup = TULIP_LINK_UP; | |
458 | } else if (mi->mi_type == TULIP_MEDIAINFO_GPR) { | |
459 | /* | |
460 | * No activity sensor? Assume all's well. | |
461 | */ | |
462 | if (mi->mi_actmask == 0) | |
463 | return TULIP_LINK_UNKNOWN; | |
464 | /* | |
465 | * Does the activity data match? | |
466 | */ | |
467 | if ((TULIP_CSR_READ(sc, csr_gp) & mi->mi_actmask) == mi->mi_actdata) | |
468 | linkup = TULIP_LINK_UP; | |
469 | } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) { | |
470 | /* | |
471 | * Assume non TP ok for now. | |
472 | */ | |
473 | if (!TULIP_IS_MEDIA_TP(sc->tulip_media)) | |
474 | return TULIP_LINK_UNKNOWN; | |
475 | if ((TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) == 0) | |
476 | linkup = TULIP_LINK_UP; | |
984263bc MD |
477 | } else if (mi->mi_type == TULIP_MEDIAINFO_SYM) { |
478 | return TULIP_LINK_UNKNOWN; | |
479 | } | |
480 | /* | |
481 | * We will wait for 3 seconds until the link goes into suspect mode. | |
482 | */ | |
483 | if (sc->tulip_flags & TULIP_LINKUP) { | |
484 | if (linkup == TULIP_LINK_UP) | |
485 | sc->tulip_probe_timeout = 3000; | |
486 | if (sc->tulip_probe_timeout > 0) | |
487 | return TULIP_LINK_UP; | |
488 | ||
489 | sc->tulip_flags &= ~TULIP_LINKUP; | |
5d2944c2 | 490 | if_printf(&sc->arpcom.ac_if, "link down: cable problem?\n"); |
984263bc | 491 | } |
984263bc MD |
492 | return TULIP_LINK_DOWN; |
493 | } | |
79fe23de | 494 | |
984263bc | 495 | static void |
79fe23de | 496 | tulip_media_poll(tulip_softc_t *sc, tulip_mediapoll_event_t event) |
984263bc | 497 | { |
984263bc MD |
498 | if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE |
499 | && event == TULIP_MEDIAPOLL_TIMER) { | |
500 | switch (tulip_media_link_monitor(sc)) { | |
501 | case TULIP_LINK_DOWN: { | |
502 | /* | |
503 | * Link Monitor failed. Probe for new media. | |
504 | */ | |
505 | event = TULIP_MEDIAPOLL_LINKFAIL; | |
506 | break; | |
507 | } | |
508 | case TULIP_LINK_UP: { | |
509 | /* | |
510 | * Check again soon. | |
511 | */ | |
512 | tulip_timeout(sc); | |
513 | return; | |
514 | } | |
515 | case TULIP_LINK_UNKNOWN: { | |
516 | /* | |
517 | * We can't tell so don't bother. | |
518 | */ | |
519 | return; | |
520 | } | |
521 | } | |
522 | } | |
523 | ||
524 | if (event == TULIP_MEDIAPOLL_LINKFAIL) { | |
525 | if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) { | |
526 | if (TULIP_DO_AUTOSENSE(sc)) { | |
984263bc | 527 | sc->tulip_media = TULIP_MEDIA_UNKNOWN; |
5d2944c2 | 528 | if (sc->arpcom.ac_if.if_flags & IFF_UP) |
984263bc MD |
529 | tulip_reset(sc); /* restart probe */ |
530 | } | |
531 | return; | |
532 | } | |
984263bc MD |
533 | } |
534 | ||
535 | if (event == TULIP_MEDIAPOLL_START) { | |
5d2944c2 | 536 | ifq_set_oactive(&sc->arpcom.ac_if.if_snd); |
984263bc MD |
537 | if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE) |
538 | return; | |
539 | sc->tulip_probe_mediamask = 0; | |
540 | sc->tulip_probe_passes = 0; | |
984263bc MD |
541 | /* |
542 | * If the SROM contained an explicit media to use, use it. | |
543 | */ | |
544 | sc->tulip_cmdmode &= ~(TULIP_CMD_RXRUN|TULIP_CMD_FULLDUPLEX); | |
545 | sc->tulip_flags |= TULIP_TRYNWAY|TULIP_PROBE1STPASS; | |
546 | sc->tulip_flags &= ~(TULIP_DIDNWAY|TULIP_PRINTMEDIA|TULIP_PRINTLINKUP); | |
547 | /* | |
548 | * connidx is defaulted to a media_unknown type. | |
549 | */ | |
550 | sc->tulip_probe_media = tulip_srom_conninfo[sc->tulip_connidx].sc_media; | |
551 | if (sc->tulip_probe_media != TULIP_MEDIA_UNKNOWN) { | |
552 | tulip_linkup(sc, sc->tulip_probe_media); | |
553 | tulip_timeout(sc); | |
554 | return; | |
555 | } | |
556 | ||
557 | if (sc->tulip_features & TULIP_HAVE_GPR) { | |
558 | sc->tulip_probe_state = TULIP_PROBE_GPRTEST; | |
559 | sc->tulip_probe_timeout = 2000; | |
560 | } else { | |
561 | sc->tulip_probe_media = TULIP_MEDIA_MAX; | |
562 | sc->tulip_probe_timeout = 0; | |
563 | sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; | |
564 | } | |
565 | } | |
566 | ||
567 | /* | |
568 | * Ignore txprobe failures or spurious callbacks. | |
569 | */ | |
570 | if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED | |
571 | && sc->tulip_probe_state != TULIP_PROBE_MEDIATEST) { | |
572 | sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; | |
573 | return; | |
574 | } | |
575 | ||
576 | /* | |
577 | * If we really transmitted a packet, then that's the media we'll use. | |
578 | */ | |
579 | if (event == TULIP_MEDIAPOLL_TXPROBE_OK || event == TULIP_MEDIAPOLL_LINKPASS) { | |
580 | if (event == TULIP_MEDIAPOLL_LINKPASS) { | |
581 | /* XXX Check media status just to be sure */ | |
582 | sc->tulip_probe_media = TULIP_MEDIA_10BASET; | |
984263bc MD |
583 | } |
584 | tulip_linkup(sc, sc->tulip_probe_media); | |
585 | tulip_timeout(sc); | |
586 | return; | |
587 | } | |
588 | ||
589 | if (sc->tulip_probe_state == TULIP_PROBE_GPRTEST) { | |
984263bc MD |
590 | /* |
591 | * Brute force. We cycle through each of the media types | |
592 | * and try to transmit a packet. | |
593 | */ | |
594 | sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; | |
595 | sc->tulip_probe_media = TULIP_MEDIA_MAX; | |
596 | sc->tulip_probe_timeout = 0; | |
597 | tulip_timeout(sc); | |
598 | return; | |
599 | } | |
600 | ||
601 | if (sc->tulip_probe_state != TULIP_PROBE_MEDIATEST | |
602 | && (sc->tulip_features & TULIP_HAVE_MII)) { | |
603 | tulip_media_t old_media = sc->tulip_probe_media; | |
604 | tulip_mii_autonegotiate(sc, sc->tulip_phyaddr); | |
605 | switch (sc->tulip_probe_state) { | |
606 | case TULIP_PROBE_FAILED: | |
607 | case TULIP_PROBE_MEDIATEST: { | |
608 | /* | |
609 | * Try the next media. | |
610 | */ | |
611 | sc->tulip_probe_mediamask |= sc->tulip_mediums[sc->tulip_probe_media]->mi_mediamask; | |
612 | sc->tulip_probe_timeout = 0; | |
613 | #ifdef notyet | |
614 | if (sc->tulip_probe_state == TULIP_PROBE_FAILED) | |
615 | break; | |
616 | if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc)) | |
617 | break; | |
618 | sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 300; | |
619 | #endif | |
620 | break; | |
621 | } | |
622 | case TULIP_PROBE_PHYAUTONEG: { | |
623 | return; | |
624 | } | |
625 | case TULIP_PROBE_INACTIVE: { | |
626 | /* | |
627 | * Only probe if we autonegotiated a media that hasn't failed. | |
628 | */ | |
629 | sc->tulip_probe_timeout = 0; | |
630 | if (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) { | |
631 | sc->tulip_probe_media = old_media; | |
632 | break; | |
633 | } | |
634 | tulip_linkup(sc, sc->tulip_probe_media); | |
635 | tulip_timeout(sc); | |
636 | return; | |
637 | } | |
638 | default: { | |
46a77a85 | 639 | #if defined(DIAGNOSTIC) |
ed20d0e3 | 640 | panic("tulip_media_poll: botch at line %d", __LINE__); |
984263bc MD |
641 | #endif |
642 | break; | |
643 | } | |
644 | } | |
645 | } | |
646 | ||
647 | if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) { | |
984263bc MD |
648 | sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; |
649 | return; | |
650 | } | |
651 | ||
652 | /* | |
653 | * switch to another media if we tried this one enough. | |
654 | */ | |
655 | if (/* event == TULIP_MEDIAPOLL_TXPROBE_FAILED || */ sc->tulip_probe_timeout <= 0) { | |
984263bc MD |
656 | /* |
657 | * Find the next media type to check for. Full Duplex | |
658 | * types are not allowed. | |
659 | */ | |
660 | do { | |
661 | sc->tulip_probe_media -= 1; | |
662 | if (sc->tulip_probe_media == TULIP_MEDIA_UNKNOWN) { | |
663 | if (++sc->tulip_probe_passes == 3) { | |
5d2944c2 IV |
664 | if_printf(&sc->arpcom.ac_if, |
665 | "autosense failed: cable problem?\n"); | |
666 | if ((sc->arpcom.ac_if.if_flags & IFF_UP) == 0) { | |
667 | sc->arpcom.ac_if.if_flags &= ~IFF_RUNNING; | |
984263bc MD |
668 | sc->tulip_probe_state = TULIP_PROBE_INACTIVE; |
669 | return; | |
670 | } | |
671 | } | |
672 | sc->tulip_flags ^= TULIP_TRYNWAY; /* XXX */ | |
673 | sc->tulip_probe_mediamask = 0; | |
674 | sc->tulip_probe_media = TULIP_MEDIA_MAX - 1; | |
675 | } | |
676 | } while (sc->tulip_mediums[sc->tulip_probe_media] == NULL | |
677 | || (sc->tulip_probe_mediamask & TULIP_BIT(sc->tulip_probe_media)) | |
678 | || TULIP_IS_MEDIA_FD(sc->tulip_probe_media)); | |
679 | ||
984263bc MD |
680 | sc->tulip_probe_timeout = TULIP_IS_MEDIA_TP(sc->tulip_probe_media) ? 2500 : 1000; |
681 | sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; | |
682 | sc->tulip_probe.probe_txprobes = 0; | |
683 | tulip_reset(sc); | |
684 | tulip_media_set(sc, sc->tulip_probe_media); | |
685 | sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; | |
686 | } | |
687 | tulip_timeout(sc); | |
688 | ||
689 | /* | |
690 | * If this is hanging off a phy, we know are doing NWAY and we have | |
691 | * forced the phy to a specific speed. Wait for link up before | |
692 | * before sending a packet. | |
693 | */ | |
694 | switch (sc->tulip_mediums[sc->tulip_probe_media]->mi_type) { | |
695 | case TULIP_MEDIAINFO_MII: { | |
696 | if (sc->tulip_probe_media != tulip_mii_phy_readspecific(sc)) | |
697 | return; | |
698 | break; | |
699 | } | |
700 | case TULIP_MEDIAINFO_SIA: { | |
701 | if (TULIP_IS_MEDIA_TP(sc->tulip_probe_media)) { | |
702 | if (TULIP_CSR_READ(sc, csr_sia_status) & TULIP_SIASTS_LINKFAIL) | |
703 | return; | |
704 | tulip_linkup(sc, sc->tulip_probe_media); | |
705 | #ifdef notyet | |
706 | if (sc->tulip_features & TULIP_HAVE_MII) | |
707 | tulip_timeout(sc); | |
708 | #endif | |
709 | return; | |
710 | } | |
711 | break; | |
712 | } | |
713 | case TULIP_MEDIAINFO_RESET: | |
714 | case TULIP_MEDIAINFO_SYM: | |
715 | case TULIP_MEDIAINFO_NONE: | |
716 | case TULIP_MEDIAINFO_GPR: { | |
717 | break; | |
718 | } | |
719 | } | |
720 | /* | |
721 | * Try to send a packet. | |
722 | */ | |
723 | tulip_txprobe(sc); | |
724 | } | |
79fe23de | 725 | |
984263bc | 726 | static void |
79fe23de | 727 | tulip_media_select(tulip_softc_t *sc) |
984263bc MD |
728 | { |
729 | if (sc->tulip_features & TULIP_HAVE_GPR) { | |
730 | TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_PINSET|sc->tulip_gpinit); | |
731 | DELAY(10); | |
732 | TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpdata); | |
733 | } | |
734 | /* | |
735 | * If this board has no media, just return | |
736 | */ | |
737 | if (sc->tulip_features & TULIP_HAVE_NOMEDIA) | |
738 | return; | |
739 | ||
740 | if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { | |
741 | TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); | |
742 | (*sc->tulip_boardsw->bd_media_poll)(sc, TULIP_MEDIAPOLL_START); | |
743 | } else { | |
744 | tulip_media_set(sc, sc->tulip_media); | |
745 | } | |
746 | } | |
79fe23de | 747 | |
984263bc | 748 | static void |
79fe23de | 749 | tulip_21040_mediainfo_init(tulip_softc_t *sc, tulip_media_t media) |
984263bc MD |
750 | { |
751 | sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_THRSHLD160 | |
752 | |TULIP_CMD_BACKOFFCTR; | |
5d2944c2 | 753 | sc->arpcom.ac_if.if_baudrate = 10000000; |
984263bc MD |
754 | |
755 | if (media == TULIP_MEDIA_10BASET || media == TULIP_MEDIA_UNKNOWN) { | |
756 | TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[0], 21040, 10BASET); | |
757 | TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[1], 21040, 10BASET_FD); | |
758 | sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; | |
759 | } | |
760 | ||
761 | if (media == TULIP_MEDIA_AUIBNC || media == TULIP_MEDIA_UNKNOWN) { | |
762 | TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[2], 21040, AUIBNC); | |
763 | } | |
764 | ||
765 | if (media == TULIP_MEDIA_UNKNOWN) { | |
766 | TULIP_MEDIAINFO_SIA_INIT(sc, &sc->tulip_mediainfo[3], 21040, EXTSIA); | |
767 | } | |
768 | } | |
769 | ||
770 | static void | |
79fe23de | 771 | tulip_21040_media_probe(tulip_softc_t *sc) |
984263bc MD |
772 | { |
773 | tulip_21040_mediainfo_init(sc, TULIP_MEDIA_UNKNOWN); | |
984263bc MD |
774 | } |
775 | ||
776 | static void | |
79fe23de | 777 | tulip_21040_10baset_only_media_probe(tulip_softc_t *sc) |
984263bc MD |
778 | { |
779 | tulip_21040_mediainfo_init(sc, TULIP_MEDIA_10BASET); | |
780 | tulip_media_set(sc, TULIP_MEDIA_10BASET); | |
781 | sc->tulip_media = TULIP_MEDIA_10BASET; | |
782 | } | |
783 | ||
784 | static void | |
79fe23de | 785 | tulip_21040_10baset_only_media_select(tulip_softc_t *sc) |
984263bc MD |
786 | { |
787 | sc->tulip_flags |= TULIP_LINKUP; | |
788 | if (sc->tulip_media == TULIP_MEDIA_10BASET_FD) { | |
789 | sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; | |
790 | sc->tulip_flags &= ~TULIP_SQETEST; | |
791 | } else { | |
792 | sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; | |
793 | sc->tulip_flags |= TULIP_SQETEST; | |
794 | } | |
795 | tulip_media_set(sc, sc->tulip_media); | |
796 | } | |
797 | ||
798 | static void | |
79fe23de | 799 | tulip_21040_auibnc_only_media_probe(tulip_softc_t *sc) |
984263bc MD |
800 | { |
801 | tulip_21040_mediainfo_init(sc, TULIP_MEDIA_AUIBNC); | |
802 | sc->tulip_flags |= TULIP_SQETEST|TULIP_LINKUP; | |
803 | tulip_media_set(sc, TULIP_MEDIA_AUIBNC); | |
804 | sc->tulip_media = TULIP_MEDIA_AUIBNC; | |
805 | } | |
806 | ||
807 | static void | |
79fe23de | 808 | tulip_21040_auibnc_only_media_select(tulip_softc_t *sc) |
984263bc MD |
809 | { |
810 | tulip_media_set(sc, TULIP_MEDIA_AUIBNC); | |
811 | sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; | |
812 | } | |
813 | ||
814 | static const tulip_boardsw_t tulip_21040_boardsw = { | |
815 | TULIP_21040_GENERIC, | |
816 | tulip_21040_media_probe, | |
817 | tulip_media_select, | |
818 | tulip_media_poll, | |
819 | }; | |
820 | ||
821 | static const tulip_boardsw_t tulip_21040_10baset_only_boardsw = { | |
822 | TULIP_21040_GENERIC, | |
823 | tulip_21040_10baset_only_media_probe, | |
824 | tulip_21040_10baset_only_media_select, | |
825 | NULL, | |
826 | }; | |
827 | ||
828 | static const tulip_boardsw_t tulip_21040_auibnc_only_boardsw = { | |
829 | TULIP_21040_GENERIC, | |
830 | tulip_21040_auibnc_only_media_probe, | |
831 | tulip_21040_auibnc_only_media_select, | |
832 | NULL, | |
833 | }; | |
79fe23de | 834 | |
984263bc | 835 | static void |
79fe23de | 836 | tulip_21041_mediainfo_init(tulip_softc_t *sc) |
984263bc | 837 | { |
79fe23de | 838 | tulip_media_info_t *mi = sc->tulip_mediainfo; |
984263bc MD |
839 | |
840 | #ifdef notyet | |
841 | if (sc->tulip_revinfo >= 0x20) { | |
842 | TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, 10BASET); | |
843 | TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, 10BASET_FD); | |
844 | TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041P2, AUI); | |
845 | TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041P2, BNC); | |
846 | return; | |
847 | } | |
848 | #endif | |
849 | TULIP_MEDIAINFO_SIA_INIT(sc, &mi[0], 21041, 10BASET); | |
850 | TULIP_MEDIAINFO_SIA_INIT(sc, &mi[1], 21041, 10BASET_FD); | |
851 | TULIP_MEDIAINFO_SIA_INIT(sc, &mi[2], 21041, AUI); | |
852 | TULIP_MEDIAINFO_SIA_INIT(sc, &mi[3], 21041, BNC); | |
853 | } | |
79fe23de | 854 | |
984263bc | 855 | static void |
79fe23de | 856 | tulip_21041_media_probe(tulip_softc_t *sc) |
984263bc | 857 | { |
5d2944c2 | 858 | sc->arpcom.ac_if.if_baudrate = 10000000; |
984263bc MD |
859 | sc->tulip_cmdmode |= TULIP_CMD_CAPTREFFCT|TULIP_CMD_ENHCAPTEFFCT |
860 | |TULIP_CMD_THRSHLD160|TULIP_CMD_BACKOFFCTR; | |
861 | sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; | |
862 | tulip_21041_mediainfo_init(sc); | |
863 | } | |
864 | ||
865 | static void | |
79fe23de | 866 | tulip_21041_media_poll(tulip_softc_t *sc, tulip_mediapoll_event_t event) |
984263bc | 867 | { |
79fe23de | 868 | uint32_t sia_status; |
984263bc | 869 | |
984263bc MD |
870 | if (event == TULIP_MEDIAPOLL_LINKFAIL) { |
871 | if (sc->tulip_probe_state != TULIP_PROBE_INACTIVE | |
872 | || !TULIP_DO_AUTOSENSE(sc)) | |
873 | return; | |
874 | sc->tulip_media = TULIP_MEDIA_UNKNOWN; | |
875 | tulip_reset(sc); /* start probe */ | |
876 | return; | |
877 | } | |
878 | ||
879 | /* | |
880 | * If we've been been asked to start a poll or link change interrupt | |
881 | * restart the probe (and reset the tulip to a known state). | |
882 | */ | |
883 | if (event == TULIP_MEDIAPOLL_START) { | |
5d2944c2 | 884 | ifq_set_oactive(&sc->arpcom.ac_if.if_snd); |
984263bc MD |
885 | sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_RXRUN); |
886 | #ifdef notyet | |
887 | if (sc->tulip_revinfo >= 0x20) { | |
888 | sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX; | |
889 | sc->tulip_flags |= TULIP_DIDNWAY; | |
890 | } | |
891 | #endif | |
892 | TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); | |
893 | sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; | |
894 | sc->tulip_probe_media = TULIP_MEDIA_10BASET; | |
895 | sc->tulip_probe_timeout = TULIP_21041_PROBE_10BASET_TIMEOUT; | |
896 | tulip_media_set(sc, TULIP_MEDIA_10BASET); | |
897 | tulip_timeout(sc); | |
898 | return; | |
899 | } | |
900 | ||
901 | if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) | |
902 | return; | |
903 | ||
904 | if (event == TULIP_MEDIAPOLL_TXPROBE_OK) { | |
984263bc MD |
905 | tulip_linkup(sc, sc->tulip_probe_media); |
906 | return; | |
907 | } | |
908 | ||
909 | sia_status = TULIP_CSR_READ(sc, csr_sia_status); | |
910 | TULIP_CSR_WRITE(sc, csr_sia_status, sia_status); | |
911 | if ((sia_status & TULIP_SIASTS_LINKFAIL) == 0) { | |
912 | if (sc->tulip_revinfo >= 0x20) { | |
913 | if (sia_status & (PHYSTS_10BASET_FD << (16 - 6))) | |
914 | sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD; | |
915 | } | |
916 | /* | |
917 | * If the link has passed LinkPass, 10baseT is the | |
918 | * proper media to use. | |
919 | */ | |
920 | tulip_linkup(sc, sc->tulip_probe_media); | |
921 | return; | |
922 | } | |
923 | ||
924 | /* | |
925 | * wait for up to 2.4 seconds for the link to reach pass state. | |
926 | * Only then start scanning the other media for activity. | |
927 | * choose media with receive activity over those without. | |
928 | */ | |
929 | if (sc->tulip_probe_media == TULIP_MEDIA_10BASET) { | |
930 | if (event != TULIP_MEDIAPOLL_TIMER) | |
931 | return; | |
932 | if (sc->tulip_probe_timeout > 0 | |
933 | && (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) == 0) { | |
934 | tulip_timeout(sc); | |
935 | return; | |
936 | } | |
937 | sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; | |
938 | sc->tulip_flags |= TULIP_WANTRXACT; | |
939 | if (sia_status & TULIP_SIASTS_OTHERRXACTIVITY) { | |
940 | sc->tulip_probe_media = TULIP_MEDIA_BNC; | |
941 | } else { | |
942 | sc->tulip_probe_media = TULIP_MEDIA_AUI; | |
943 | } | |
944 | tulip_media_set(sc, sc->tulip_probe_media); | |
945 | tulip_timeout(sc); | |
946 | return; | |
947 | } | |
948 | ||
949 | /* | |
950 | * If we failed, clear the txprobe active flag. | |
951 | */ | |
952 | if (event == TULIP_MEDIAPOLL_TXPROBE_FAILED) | |
953 | sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; | |
954 | ||
955 | ||
956 | if (event == TULIP_MEDIAPOLL_TIMER) { | |
957 | /* | |
958 | * If we've received something, then that's our link! | |
959 | */ | |
960 | if (sc->tulip_flags & TULIP_RXACT) { | |
961 | tulip_linkup(sc, sc->tulip_probe_media); | |
962 | return; | |
963 | } | |
964 | /* | |
965 | * if no txprobe active | |
966 | */ | |
967 | if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0 | |
968 | && ((sc->tulip_flags & TULIP_WANTRXACT) == 0 | |
969 | || (sia_status & TULIP_SIASTS_RXACTIVITY))) { | |
970 | sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; | |
971 | tulip_txprobe(sc); | |
972 | tulip_timeout(sc); | |
973 | return; | |
974 | } | |
975 | /* | |
976 | * Take 2 passes through before deciding to not | |
977 | * wait for receive activity. Then take another | |
978 | * two passes before spitting out a warning. | |
979 | */ | |
980 | if (sc->tulip_probe_timeout <= 0) { | |
981 | if (sc->tulip_flags & TULIP_WANTRXACT) { | |
982 | sc->tulip_flags &= ~TULIP_WANTRXACT; | |
983 | sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; | |
984 | } else { | |
5d2944c2 IV |
985 | if_printf(&sc->arpcom.ac_if, |
986 | "autosense failed: cable problem?\n"); | |
987 | if ((sc->arpcom.ac_if.if_flags & IFF_UP) == 0) { | |
988 | sc->arpcom.ac_if.if_flags &= ~IFF_RUNNING; | |
984263bc MD |
989 | sc->tulip_probe_state = TULIP_PROBE_INACTIVE; |
990 | return; | |
991 | } | |
992 | } | |
993 | } | |
994 | } | |
995 | ||
996 | /* | |
997 | * Since this media failed to probe, try the other one. | |
998 | */ | |
999 | sc->tulip_probe_timeout = TULIP_21041_PROBE_AUIBNC_TIMEOUT; | |
1000 | if (sc->tulip_probe_media == TULIP_MEDIA_AUI) { | |
1001 | sc->tulip_probe_media = TULIP_MEDIA_BNC; | |
1002 | } else { | |
1003 | sc->tulip_probe_media = TULIP_MEDIA_AUI; | |
1004 | } | |
1005 | tulip_media_set(sc, sc->tulip_probe_media); | |
1006 | sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; | |
1007 | tulip_timeout(sc); | |
1008 | } | |
1009 | ||
1010 | static const tulip_boardsw_t tulip_21041_boardsw = { | |
1011 | TULIP_21041_GENERIC, | |
1012 | tulip_21041_media_probe, | |
1013 | tulip_media_select, | |
1014 | tulip_21041_media_poll | |
1015 | }; | |
79fe23de | 1016 | |
984263bc MD |
1017 | static const tulip_phy_attr_t tulip_mii_phy_attrlist[] = { |
1018 | { 0x20005c00, 0, /* 08-00-17 */ | |
1019 | { | |
1020 | { 0x19, 0x0040, 0x0040 }, /* 10TX */ | |
1021 | { 0x19, 0x0040, 0x0000 }, /* 100TX */ | |
1022 | }, | |
984263bc MD |
1023 | }, |
1024 | { 0x0281F400, 0, /* 00-A0-7D */ | |
1025 | { | |
1026 | { 0x12, 0x0010, 0x0000 }, /* 10T */ | |
1027 | { }, /* 100TX */ | |
1028 | { 0x12, 0x0010, 0x0010 }, /* 100T4 */ | |
1029 | { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */ | |
1030 | }, | |
984263bc MD |
1031 | }, |
1032 | #if 0 | |
1033 | { 0x0015F420, 0, /* 00-A0-7D */ | |
1034 | { | |
1035 | { 0x12, 0x0010, 0x0000 }, /* 10T */ | |
1036 | { }, /* 100TX */ | |
1037 | { 0x12, 0x0010, 0x0010 }, /* 100T4 */ | |
1038 | { 0x12, 0x0008, 0x0008 }, /* FULL_DUPLEX */ | |
1039 | }, | |
984263bc MD |
1040 | }, |
1041 | #endif | |
1042 | { 0x0281F400, 0, /* 00-A0-BE */ | |
1043 | { | |
1044 | { 0x11, 0x8000, 0x0000 }, /* 10T */ | |
1045 | { 0x11, 0x8000, 0x8000 }, /* 100TX */ | |
1046 | { }, /* 100T4 */ | |
1047 | { 0x11, 0x4000, 0x4000 }, /* FULL_DUPLEX */ | |
1048 | }, | |
984263bc MD |
1049 | }, |
1050 | { 0 } | |
1051 | }; | |
79fe23de | 1052 | |
984263bc | 1053 | static tulip_media_t |
79fe23de | 1054 | tulip_mii_phy_readspecific(tulip_softc_t *sc) |
984263bc MD |
1055 | { |
1056 | const tulip_phy_attr_t *attr; | |
1057 | u_int16_t data; | |
1058 | u_int32_t id; | |
1059 | unsigned idx = 0; | |
1060 | static const tulip_media_t table[] = { | |
1061 | TULIP_MEDIA_UNKNOWN, | |
1062 | TULIP_MEDIA_10BASET, | |
1063 | TULIP_MEDIA_100BASETX, | |
1064 | TULIP_MEDIA_100BASET4, | |
1065 | TULIP_MEDIA_UNKNOWN, | |
1066 | TULIP_MEDIA_10BASET_FD, | |
1067 | TULIP_MEDIA_100BASETX_FD, | |
1068 | TULIP_MEDIA_UNKNOWN | |
1069 | }; | |
1070 | ||
1071 | /* | |
1072 | * Don't read phy specific registers if link is not up. | |
1073 | */ | |
1074 | data = tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_STATUS); | |
1075 | if ((data & (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) != (PHYSTS_LINK_UP|PHYSTS_EXTENDED_REGS)) | |
1076 | return TULIP_MEDIA_UNKNOWN; | |
1077 | ||
1078 | id = (tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDLOW) << 16) | | |
1079 | tulip_mii_readreg(sc, sc->tulip_phyaddr, PHYREG_IDHIGH); | |
1080 | for (attr = tulip_mii_phy_attrlist;; attr++) { | |
1081 | if (attr->attr_id == 0) | |
1082 | return TULIP_MEDIA_UNKNOWN; | |
1083 | if ((id & ~0x0F) == attr->attr_id) | |
1084 | break; | |
1085 | } | |
1086 | ||
1087 | if (attr->attr_modes[PHY_MODE_100TX].pm_regno) { | |
79fe23de | 1088 | const tulip_phy_modedata_t *pm = &attr->attr_modes[PHY_MODE_100TX]; |
984263bc MD |
1089 | data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); |
1090 | if ((data & pm->pm_mask) == pm->pm_value) | |
1091 | idx = 2; | |
1092 | } | |
1093 | if (idx == 0 && attr->attr_modes[PHY_MODE_100T4].pm_regno) { | |
79fe23de | 1094 | const tulip_phy_modedata_t *pm = &attr->attr_modes[PHY_MODE_100T4]; |
984263bc MD |
1095 | data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); |
1096 | if ((data & pm->pm_mask) == pm->pm_value) | |
1097 | idx = 3; | |
1098 | } | |
1099 | if (idx == 0 && attr->attr_modes[PHY_MODE_10T].pm_regno) { | |
79fe23de | 1100 | const tulip_phy_modedata_t *pm = &attr->attr_modes[PHY_MODE_10T]; |
984263bc MD |
1101 | data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); |
1102 | if ((data & pm->pm_mask) == pm->pm_value) | |
1103 | idx = 1; | |
1104 | } | |
1105 | if (idx != 0 && attr->attr_modes[PHY_MODE_FULLDUPLEX].pm_regno) { | |
79fe23de | 1106 | const tulip_phy_modedata_t *pm = &attr->attr_modes[PHY_MODE_FULLDUPLEX]; |
984263bc MD |
1107 | data = tulip_mii_readreg(sc, sc->tulip_phyaddr, pm->pm_regno); |
1108 | idx += ((data & pm->pm_mask) == pm->pm_value ? 4 : 0); | |
1109 | } | |
1110 | return table[idx]; | |
1111 | } | |
79fe23de JS |
1112 | |
1113 | static u_int | |
1114 | tulip_mii_get_phyaddr(tulip_softc_t *sc, u_int offset) | |
984263bc | 1115 | { |
79fe23de | 1116 | u_int phyaddr; |
984263bc MD |
1117 | |
1118 | for (phyaddr = 1; phyaddr < 32; phyaddr++) { | |
79fe23de | 1119 | u_int status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); |
984263bc MD |
1120 | if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET) |
1121 | continue; | |
1122 | if (offset == 0) | |
1123 | return phyaddr; | |
1124 | offset--; | |
1125 | } | |
1126 | if (offset == 0) { | |
79fe23de | 1127 | u_int status = tulip_mii_readreg(sc, 0, PHYREG_STATUS); |
984263bc MD |
1128 | if (status == 0 || status == 0xFFFF || status < PHYSTS_10BASET) |
1129 | return TULIP_MII_NOPHY; | |
1130 | return 0; | |
1131 | } | |
1132 | return TULIP_MII_NOPHY; | |
1133 | } | |
79fe23de | 1134 | |
984263bc | 1135 | static int |
79fe23de | 1136 | tulip_mii_map_abilities(tulip_softc_t *sc, u_int abilities) |
984263bc MD |
1137 | { |
1138 | sc->tulip_abilities = abilities; | |
1139 | if (abilities & PHYSTS_100BASETX_FD) { | |
1140 | sc->tulip_probe_media = TULIP_MEDIA_100BASETX_FD; | |
1141 | } else if (abilities & PHYSTS_100BASET4) { | |
1142 | sc->tulip_probe_media = TULIP_MEDIA_100BASET4; | |
1143 | } else if (abilities & PHYSTS_100BASETX) { | |
1144 | sc->tulip_probe_media = TULIP_MEDIA_100BASETX; | |
1145 | } else if (abilities & PHYSTS_10BASET_FD) { | |
1146 | sc->tulip_probe_media = TULIP_MEDIA_10BASET_FD; | |
1147 | } else if (abilities & PHYSTS_10BASET) { | |
1148 | sc->tulip_probe_media = TULIP_MEDIA_10BASET; | |
1149 | } else { | |
1150 | sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; | |
1151 | return 0; | |
1152 | } | |
1153 | sc->tulip_probe_state = TULIP_PROBE_INACTIVE; | |
1154 | return 1; | |
1155 | } | |
1156 | ||
1157 | static void | |
79fe23de | 1158 | tulip_mii_autonegotiate(tulip_softc_t *sc, u_int phyaddr) |
984263bc MD |
1159 | { |
1160 | switch (sc->tulip_probe_state) { | |
1161 | case TULIP_PROBE_MEDIATEST: | |
1162 | case TULIP_PROBE_INACTIVE: { | |
1163 | sc->tulip_flags |= TULIP_DIDNWAY; | |
1164 | tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, PHYCTL_RESET); | |
1165 | sc->tulip_probe_timeout = 3000; | |
1166 | sc->tulip_intrmask |= TULIP_STS_ABNRMLINTR|TULIP_STS_NORMALINTR; | |
1167 | sc->tulip_probe_state = TULIP_PROBE_PHYRESET; | |
1168 | /* FALL THROUGH */ | |
1169 | } | |
1170 | case TULIP_PROBE_PHYRESET: { | |
79fe23de JS |
1171 | uint32_t status; |
1172 | uint32_t data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL); | |
984263bc MD |
1173 | if (data & PHYCTL_RESET) { |
1174 | if (sc->tulip_probe_timeout > 0) { | |
1175 | tulip_timeout(sc); | |
1176 | return; | |
1177 | } | |
5d2944c2 | 1178 | if_printf(&sc->arpcom.ac_if, |
b3e6c01b | 1179 | "(phy%d): error: reset of PHY never completed!\n", phyaddr); |
984263bc MD |
1180 | sc->tulip_flags &= ~TULIP_TXPROBE_ACTIVE; |
1181 | sc->tulip_probe_state = TULIP_PROBE_FAILED; | |
5d2944c2 | 1182 | sc->arpcom.ac_if.if_flags &= ~(IFF_UP|IFF_RUNNING); |
984263bc MD |
1183 | return; |
1184 | } | |
1185 | status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); | |
1186 | if ((status & PHYSTS_CAN_AUTONEG) == 0) { | |
984263bc MD |
1187 | sc->tulip_flags &= ~TULIP_DIDNWAY; |
1188 | sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; | |
1189 | return; | |
1190 | } | |
1191 | if (tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT) != ((status >> 6) | 0x01)) | |
1192 | tulip_mii_writereg(sc, phyaddr, PHYREG_AUTONEG_ADVERTISEMENT, (status >> 6) | 0x01); | |
1193 | tulip_mii_writereg(sc, phyaddr, PHYREG_CONTROL, data|PHYCTL_AUTONEG_RESTART|PHYCTL_AUTONEG_ENABLE); | |
1194 | data = tulip_mii_readreg(sc, phyaddr, PHYREG_CONTROL); | |
984263bc MD |
1195 | sc->tulip_probe_state = TULIP_PROBE_PHYAUTONEG; |
1196 | sc->tulip_probe_timeout = 3000; | |
1197 | /* FALL THROUGH */ | |
1198 | } | |
1199 | case TULIP_PROBE_PHYAUTONEG: { | |
1200 | u_int32_t status = tulip_mii_readreg(sc, phyaddr, PHYREG_STATUS); | |
1201 | u_int32_t data; | |
1202 | if ((status & PHYSTS_AUTONEG_DONE) == 0) { | |
1203 | if (sc->tulip_probe_timeout > 0) { | |
1204 | tulip_timeout(sc); | |
1205 | return; | |
1206 | } | |
984263bc MD |
1207 | sc->tulip_flags &= ~TULIP_DIDNWAY; |
1208 | sc->tulip_probe_state = TULIP_PROBE_MEDIATEST; | |
1209 | return; | |
1210 | } | |
1211 | data = tulip_mii_readreg(sc, phyaddr, PHYREG_AUTONEG_ABILITIES); | |
984263bc MD |
1212 | data = (data << 6) & status; |
1213 | if (!tulip_mii_map_abilities(sc, data)) | |
1214 | sc->tulip_flags &= ~TULIP_DIDNWAY; | |
1215 | return; | |
1216 | } | |
1217 | default: { | |
1218 | #if defined(DIAGNOSTIC) | |
ed20d0e3 | 1219 | panic("tulip_media_poll: botch at line %d", __LINE__); |
984263bc MD |
1220 | #endif |
1221 | break; | |
1222 | } | |
1223 | } | |
984263bc | 1224 | } |
79fe23de | 1225 | |
984263bc | 1226 | static void |
79fe23de | 1227 | tulip_2114x_media_preset(tulip_softc_t *sc) |
984263bc MD |
1228 | { |
1229 | const tulip_media_info_t *mi = NULL; | |
9e758ef5 | 1230 | tulip_media_t media; |
984263bc MD |
1231 | |
1232 | if (sc->tulip_probe_state == TULIP_PROBE_INACTIVE) | |
1233 | media = sc->tulip_media; | |
1234 | else | |
1235 | media = sc->tulip_probe_media; | |
1236 | ||
1237 | sc->tulip_cmdmode &= ~TULIP_CMD_PORTSELECT; | |
1238 | sc->tulip_flags &= ~TULIP_SQETEST; | |
1239 | if (media != TULIP_MEDIA_UNKNOWN && media != TULIP_MEDIA_MAX) { | |
984263bc MD |
1240 | mi = sc->tulip_mediums[media]; |
1241 | if (mi->mi_type == TULIP_MEDIAINFO_MII) { | |
1242 | sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT; | |
1243 | } else if (mi->mi_type == TULIP_MEDIAINFO_GPR | |
1244 | || mi->mi_type == TULIP_MEDIAINFO_SYM) { | |
1245 | sc->tulip_cmdmode &= ~TULIP_GPR_CMDBITS; | |
1246 | sc->tulip_cmdmode |= mi->mi_cmdmode; | |
1247 | } else if (mi->mi_type == TULIP_MEDIAINFO_SIA) { | |
1248 | TULIP_CSR_WRITE(sc, csr_sia_connectivity, TULIP_SIACONN_RESET); | |
1249 | } | |
984263bc MD |
1250 | } |
1251 | switch (media) { | |
1252 | case TULIP_MEDIA_BNC: | |
1253 | case TULIP_MEDIA_AUI: | |
1254 | case TULIP_MEDIA_10BASET: { | |
1255 | sc->tulip_cmdmode &= ~TULIP_CMD_FULLDUPLEX; | |
1256 | sc->tulip_cmdmode |= TULIP_CMD_TXTHRSHLDCTL; | |
5d2944c2 | 1257 | sc->arpcom.ac_if.if_baudrate = 10000000; |
984263bc MD |
1258 | sc->tulip_flags |= TULIP_SQETEST; |
1259 | break; | |
1260 | } | |
1261 | case TULIP_MEDIA_10BASET_FD: { | |
1262 | sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL; | |
5d2944c2 | 1263 | sc->arpcom.ac_if.if_baudrate = 10000000; |
984263bc MD |
1264 | break; |
1265 | } | |
1266 | case TULIP_MEDIA_100BASEFX: | |
1267 | case TULIP_MEDIA_100BASET4: | |
1268 | case TULIP_MEDIA_100BASETX: { | |
1269 | sc->tulip_cmdmode &= ~(TULIP_CMD_FULLDUPLEX|TULIP_CMD_TXTHRSHLDCTL); | |
1270 | sc->tulip_cmdmode |= TULIP_CMD_PORTSELECT; | |
5d2944c2 | 1271 | sc->arpcom.ac_if.if_baudrate = 100000000; |
984263bc MD |
1272 | break; |
1273 | } | |
1274 | case TULIP_MEDIA_100BASEFX_FD: | |
1275 | case TULIP_MEDIA_100BASETX_FD: { | |
1276 | sc->tulip_cmdmode |= TULIP_CMD_FULLDUPLEX|TULIP_CMD_PORTSELECT; | |
1277 | sc->tulip_cmdmode &= ~TULIP_CMD_TXTHRSHLDCTL; | |
5d2944c2 | 1278 | sc->arpcom.ac_if.if_baudrate = 100000000; |
984263bc MD |
1279 | break; |
1280 | } | |
1281 | default: { | |
1282 | break; | |
1283 | } | |
1284 | } | |
1285 | TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); | |
1286 | } | |
79fe23de | 1287 | |
984263bc MD |
1288 | /* |
1289 | ******************************************************************** | |
1290 | * Start of 21140/21140A support which does not use the MII interface | |
1291 | */ | |
79fe23de | 1292 | |
984263bc | 1293 | static void |
79fe23de | 1294 | tulip_null_media_poll(tulip_softc_t *sc, tulip_mediapoll_event_t event) |
984263bc | 1295 | { |
984263bc | 1296 | #if defined(DIAGNOSTIC) |
5d2944c2 | 1297 | if_printf(&sc->arpcom.ac_if, "botch(media_poll) at line %d\n", __LINE__); |
984263bc MD |
1298 | #endif |
1299 | } | |
1300 | ||
79fe23de JS |
1301 | static void |
1302 | tulip_21140_mediainit(tulip_softc_t *sc, tulip_media_info_t *mip, | |
1303 | tulip_media_t media, u_int gpdata, u_int cmdmode) | |
984263bc MD |
1304 | { |
1305 | sc->tulip_mediums[media] = mip; | |
1306 | mip->mi_type = TULIP_MEDIAINFO_GPR; | |
1307 | mip->mi_cmdmode = cmdmode; | |
1308 | mip->mi_gpdata = gpdata; | |
1309 | } | |
79fe23de | 1310 | |
984263bc | 1311 | static void |
79fe23de | 1312 | tulip_21140_evalboard_media_probe(tulip_softc_t *sc) |
984263bc MD |
1313 | { |
1314 | tulip_media_info_t *mip = sc->tulip_mediainfo; | |
1315 | ||
1316 | sc->tulip_gpinit = TULIP_GP_EB_PINS; | |
1317 | sc->tulip_gpdata = TULIP_GP_EB_INIT; | |
1318 | TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS); | |
1319 | TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT); | |
1320 | TULIP_CSR_WRITE(sc, csr_command, | |
1321 | TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | | |
1322 | TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); | |
1323 | TULIP_CSR_WRITE(sc, csr_command, | |
1324 | TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); | |
1325 | DELAY(1000000); | |
1326 | if ((TULIP_CSR_READ(sc, csr_gp) & TULIP_GP_EB_OK100) != 0) { | |
1327 | sc->tulip_media = TULIP_MEDIA_10BASET; | |
1328 | } else { | |
1329 | sc->tulip_media = TULIP_MEDIA_100BASETX; | |
1330 | } | |
1331 | tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, | |
1332 | TULIP_GP_EB_INIT, | |
1333 | TULIP_CMD_TXTHRSHLDCTL); | |
1334 | tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, | |
1335 | TULIP_GP_EB_INIT, | |
1336 | TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); | |
1337 | tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, | |
1338 | TULIP_GP_EB_INIT, | |
1339 | TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION | |
1340 | |TULIP_CMD_SCRAMBLER); | |
1341 | tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, | |
1342 | TULIP_GP_EB_INIT, | |
1343 | TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION | |
1344 | |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); | |
1345 | } | |
1346 | ||
1347 | static const tulip_boardsw_t tulip_21140_eb_boardsw = { | |
1348 | TULIP_21140_DEC_EB, | |
1349 | tulip_21140_evalboard_media_probe, | |
1350 | tulip_media_select, | |
1351 | tulip_null_media_poll, | |
1352 | tulip_2114x_media_preset, | |
1353 | }; | |
79fe23de | 1354 | |
984263bc | 1355 | static void |
79fe23de | 1356 | tulip_21140_accton_media_probe(tulip_softc_t *sc) |
984263bc MD |
1357 | { |
1358 | tulip_media_info_t *mip = sc->tulip_mediainfo; | |
79fe23de | 1359 | u_int gpdata; |
984263bc MD |
1360 | |
1361 | sc->tulip_gpinit = TULIP_GP_EB_PINS; | |
1362 | sc->tulip_gpdata = TULIP_GP_EB_INIT; | |
1363 | TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_PINS); | |
1364 | TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EB_INIT); | |
1365 | TULIP_CSR_WRITE(sc, csr_command, | |
1366 | TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | | |
1367 | TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); | |
1368 | TULIP_CSR_WRITE(sc, csr_command, | |
1369 | TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); | |
1370 | DELAY(1000000); | |
1371 | gpdata = TULIP_CSR_READ(sc, csr_gp); | |
1372 | if ((gpdata & TULIP_GP_EN1207_UTP_INIT) == 0) { | |
1373 | sc->tulip_media = TULIP_MEDIA_10BASET; | |
1374 | } else { | |
1375 | if ((gpdata & TULIP_GP_EN1207_BNC_INIT) == 0) { | |
1376 | sc->tulip_media = TULIP_MEDIA_BNC; | |
1377 | } else { | |
1378 | sc->tulip_media = TULIP_MEDIA_100BASETX; | |
1379 | } | |
1380 | } | |
1381 | tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_BNC, | |
1382 | TULIP_GP_EN1207_BNC_INIT, | |
1383 | TULIP_CMD_TXTHRSHLDCTL); | |
1384 | tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, | |
1385 | TULIP_GP_EN1207_UTP_INIT, | |
1386 | TULIP_CMD_TXTHRSHLDCTL); | |
1387 | tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, | |
1388 | TULIP_GP_EN1207_UTP_INIT, | |
1389 | TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); | |
1390 | tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, | |
1391 | TULIP_GP_EN1207_100_INIT, | |
1392 | TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION | |
1393 | |TULIP_CMD_SCRAMBLER); | |
1394 | tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, | |
1395 | TULIP_GP_EN1207_100_INIT, | |
1396 | TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION | |
1397 | |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); | |
1398 | } | |
1399 | ||
1400 | static const tulip_boardsw_t tulip_21140_accton_boardsw = { | |
1401 | TULIP_21140_EN1207, | |
1402 | tulip_21140_accton_media_probe, | |
1403 | tulip_media_select, | |
1404 | tulip_null_media_poll, | |
1405 | tulip_2114x_media_preset, | |
1406 | }; | |
79fe23de | 1407 | |
984263bc | 1408 | static void |
79fe23de | 1409 | tulip_21140_smc9332_media_probe(tulip_softc_t *sc) |
984263bc MD |
1410 | { |
1411 | tulip_media_info_t *mip = sc->tulip_mediainfo; | |
1412 | int idx, cnt = 0; | |
1413 | ||
1414 | TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT|TULIP_CMD_MUSTBEONE); | |
1415 | TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); | |
1416 | DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at | |
1417 | 33MHz that comes to two microseconds but wait a | |
1418 | bit longer anyways) */ | |
1419 | TULIP_CSR_WRITE(sc, csr_command, TULIP_CMD_PORTSELECT | | |
1420 | TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); | |
1421 | sc->tulip_gpinit = TULIP_GP_SMC_9332_PINS; | |
1422 | sc->tulip_gpdata = TULIP_GP_SMC_9332_INIT; | |
1423 | TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_PINS|TULIP_GP_PINSET); | |
1424 | TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_SMC_9332_INIT); | |
1425 | DELAY(200000); | |
1426 | for (idx = 1000; idx > 0; idx--) { | |
1427 | u_int32_t csr = TULIP_CSR_READ(sc, csr_gp); | |
1428 | if ((csr & (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) == (TULIP_GP_SMC_9332_OK10|TULIP_GP_SMC_9332_OK100)) { | |
1429 | if (++cnt > 100) | |
1430 | break; | |
1431 | } else if ((csr & TULIP_GP_SMC_9332_OK10) == 0) { | |
1432 | break; | |
1433 | } else { | |
1434 | cnt = 0; | |
1435 | } | |
1436 | DELAY(1000); | |
1437 | } | |
1438 | sc->tulip_media = cnt > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET; | |
1439 | tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, | |
1440 | TULIP_GP_SMC_9332_INIT, | |
1441 | TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION | |
1442 | |TULIP_CMD_SCRAMBLER); | |
1443 | tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, | |
1444 | TULIP_GP_SMC_9332_INIT, | |
1445 | TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION | |
1446 | |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); | |
1447 | tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, | |
1448 | TULIP_GP_SMC_9332_INIT, | |
1449 | TULIP_CMD_TXTHRSHLDCTL); | |
1450 | tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, | |
1451 | TULIP_GP_SMC_9332_INIT, | |
1452 | TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); | |
1453 | } | |
1454 | ||
1455 | static const tulip_boardsw_t tulip_21140_smc9332_boardsw = { | |
1456 | TULIP_21140_SMC_9332, | |
1457 | tulip_21140_smc9332_media_probe, | |
1458 | tulip_media_select, | |
1459 | tulip_null_media_poll, | |
1460 | tulip_2114x_media_preset, | |
1461 | }; | |
79fe23de | 1462 | |
984263bc | 1463 | static void |
79fe23de | 1464 | tulip_21140_cogent_em100_media_probe(tulip_softc_t *sc) |
984263bc MD |
1465 | { |
1466 | tulip_media_info_t *mip = sc->tulip_mediainfo; | |
9e758ef5 | 1467 | uint32_t cmdmode; |
984263bc MD |
1468 | |
1469 | sc->tulip_gpinit = TULIP_GP_EM100_PINS; | |
1470 | sc->tulip_gpdata = TULIP_GP_EM100_INIT; | |
1471 | TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_PINS); | |
1472 | TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_EM100_INIT); | |
1473 | ||
1474 | cmdmode = TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION|TULIP_CMD_MUSTBEONE; | |
1475 | cmdmode &= ~(TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_SCRAMBLER); | |
1476 | if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) { | |
1477 | TULIP_CSR_WRITE(sc, csr_command, cmdmode); | |
1478 | sc->tulip_media = TULIP_MEDIA_100BASEFX; | |
1479 | ||
1480 | tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX, | |
1481 | TULIP_GP_EM100_INIT, | |
1482 | TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION); | |
1483 | tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASEFX_FD, | |
1484 | TULIP_GP_EM100_INIT, | |
1485 | TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION | |
1486 | |TULIP_CMD_FULLDUPLEX); | |
1487 | } else { | |
1488 | TULIP_CSR_WRITE(sc, csr_command, cmdmode|TULIP_CMD_SCRAMBLER); | |
1489 | sc->tulip_media = TULIP_MEDIA_100BASETX; | |
1490 | tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, | |
1491 | TULIP_GP_EM100_INIT, | |
1492 | TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION | |
1493 | |TULIP_CMD_SCRAMBLER); | |
1494 | tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, | |
1495 | TULIP_GP_EM100_INIT, | |
1496 | TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION | |
1497 | |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); | |
1498 | } | |
1499 | } | |
1500 | ||
1501 | static const tulip_boardsw_t tulip_21140_cogent_em100_boardsw = { | |
1502 | TULIP_21140_COGENT_EM100, | |
1503 | tulip_21140_cogent_em100_media_probe, | |
1504 | tulip_media_select, | |
1505 | tulip_null_media_poll, | |
1506 | tulip_2114x_media_preset | |
1507 | }; | |
79fe23de | 1508 | |
984263bc | 1509 | static void |
79fe23de | 1510 | tulip_21140_znyx_zx34x_media_probe(tulip_softc_t *sc) |
984263bc MD |
1511 | { |
1512 | tulip_media_info_t *mip = sc->tulip_mediainfo; | |
1513 | int cnt10 = 0, cnt100 = 0, idx; | |
1514 | ||
1515 | sc->tulip_gpinit = TULIP_GP_ZX34X_PINS; | |
1516 | sc->tulip_gpdata = TULIP_GP_ZX34X_INIT; | |
1517 | TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_PINS); | |
1518 | TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ZX34X_INIT); | |
1519 | TULIP_CSR_WRITE(sc, csr_command, | |
1520 | TULIP_CSR_READ(sc, csr_command) | TULIP_CMD_PORTSELECT | | |
1521 | TULIP_CMD_PCSFUNCTION | TULIP_CMD_SCRAMBLER | TULIP_CMD_MUSTBEONE); | |
1522 | TULIP_CSR_WRITE(sc, csr_command, | |
1523 | TULIP_CSR_READ(sc, csr_command) & ~TULIP_CMD_TXTHRSHLDCTL); | |
1524 | ||
1525 | DELAY(200000); | |
1526 | for (idx = 1000; idx > 0; idx--) { | |
79fe23de | 1527 | uint32_t csr = TULIP_CSR_READ(sc, csr_gp); |
984263bc MD |
1528 | if ((csr & (TULIP_GP_ZX34X_LNKFAIL|TULIP_GP_ZX34X_SYMDET|TULIP_GP_ZX34X_SIGDET)) == (TULIP_GP_ZX34X_LNKFAIL|TULIP_GP_ZX34X_SYMDET|TULIP_GP_ZX34X_SIGDET)) { |
1529 | if (++cnt100 > 100) | |
1530 | break; | |
1531 | } else if ((csr & TULIP_GP_ZX34X_LNKFAIL) == 0) { | |
1532 | if (++cnt10 > 100) | |
1533 | break; | |
1534 | } else { | |
1535 | cnt10 = 0; | |
1536 | cnt100 = 0; | |
1537 | } | |
1538 | DELAY(1000); | |
1539 | } | |
1540 | sc->tulip_media = cnt100 > 100 ? TULIP_MEDIA_100BASETX : TULIP_MEDIA_10BASET; | |
1541 | tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET, | |
1542 | TULIP_GP_ZX34X_INIT, | |
1543 | TULIP_CMD_TXTHRSHLDCTL); | |
1544 | tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_10BASET_FD, | |
1545 | TULIP_GP_ZX34X_INIT, | |
1546 | TULIP_CMD_TXTHRSHLDCTL|TULIP_CMD_FULLDUPLEX); | |
1547 | tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX, | |
1548 | TULIP_GP_ZX34X_INIT, | |
1549 | TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION | |
1550 | |TULIP_CMD_SCRAMBLER); | |
1551 | tulip_21140_mediainit(sc, mip++, TULIP_MEDIA_100BASETX_FD, | |
1552 | TULIP_GP_ZX34X_INIT, | |
1553 | TULIP_CMD_PORTSELECT|TULIP_CMD_PCSFUNCTION | |
1554 | |TULIP_CMD_SCRAMBLER|TULIP_CMD_FULLDUPLEX); | |
1555 | } | |
1556 | ||
1557 | static const tulip_boardsw_t tulip_21140_znyx_zx34x_boardsw = { | |
1558 | TULIP_21140_ZNYX_ZX34X, | |
1559 | tulip_21140_znyx_zx34x_media_probe, | |
1560 | tulip_media_select, | |
1561 | tulip_null_media_poll, | |
1562 | tulip_2114x_media_preset, | |
1563 | }; | |
79fe23de | 1564 | |
984263bc | 1565 | static void |
79fe23de | 1566 | tulip_2114x_media_probe(tulip_softc_t *sc) |
984263bc | 1567 | { |
79fe23de JS |
1568 | sc->tulip_cmdmode |= TULIP_CMD_MUSTBEONE | TULIP_CMD_BACKOFFCTR | |
1569 | TULIP_CMD_THRSHLD72; | |
984263bc MD |
1570 | } |
1571 | ||
1572 | static const tulip_boardsw_t tulip_2114x_isv_boardsw = { | |
1573 | TULIP_21140_ISV, | |
1574 | tulip_2114x_media_probe, | |
1575 | tulip_media_select, | |
1576 | tulip_media_poll, | |
1577 | tulip_2114x_media_preset, | |
1578 | }; | |
79fe23de | 1579 | |
984263bc MD |
1580 | /* |
1581 | * ******** END of chip-specific handlers. *********** | |
1582 | */ | |
79fe23de | 1583 | |
984263bc MD |
1584 | /* |
1585 | * Code the read the SROM and MII bit streams (I2C) | |
1586 | */ | |
79fe23de JS |
1587 | #define EMIT do { \ |
1588 | TULIP_CSR_WRITE(sc, csr_srom_mii, csr); \ | |
1589 | DELAY(1); \ | |
1590 | } while (0) | |
984263bc MD |
1591 | |
1592 | static void | |
79fe23de | 1593 | tulip_srom_idle(tulip_softc_t *sc) |
984263bc | 1594 | { |
79fe23de | 1595 | u_int bit, csr; |
984263bc MD |
1596 | |
1597 | csr = SROMSEL ; EMIT; | |
1598 | csr = SROMSEL | SROMRD; EMIT; | |
1599 | csr ^= SROMCS; EMIT; | |
1600 | csr ^= SROMCLKON; EMIT; | |
1601 | ||
1602 | /* | |
1603 | * Write 25 cycles of 0 which will force the SROM to be idle. | |
1604 | */ | |
1605 | for (bit = 3 + SROM_BITWIDTH + 16; bit > 0; bit--) { | |
1606 | csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ | |
1607 | csr ^= SROMCLKON; EMIT; /* clock high; data valid */ | |
1608 | } | |
1609 | csr ^= SROMCLKOFF; EMIT; | |
1610 | csr ^= SROMCS; EMIT; | |
1611 | csr = 0; EMIT; | |
1612 | } | |
1613 | ||
984263bc | 1614 | static void |
79fe23de | 1615 | tulip_srom_read(tulip_softc_t *sc) |
984263bc | 1616 | { |
79fe23de JS |
1617 | const u_int bitwidth = SROM_BITWIDTH; |
1618 | const u_int cmdmask = (SROMCMD_RD << bitwidth); | |
1619 | const u_int msb = 1 << (bitwidth + 3 - 1); | |
1620 | u_int idx, lastidx = (1 << bitwidth) - 1; | |
984263bc MD |
1621 | |
1622 | tulip_srom_idle(sc); | |
1623 | ||
1624 | for (idx = 0; idx <= lastidx; idx++) { | |
79fe23de | 1625 | u_int lastbit, data, bits, bit, csr; |
984263bc MD |
1626 | csr = SROMSEL ; EMIT; |
1627 | csr = SROMSEL | SROMRD; EMIT; | |
1628 | csr ^= SROMCSON; EMIT; | |
1629 | csr ^= SROMCLKON; EMIT; | |
1630 | ||
1631 | lastbit = 0; | |
1632 | for (bits = idx|cmdmask, bit = bitwidth + 3; bit > 0; bit--, bits <<= 1) { | |
79fe23de | 1633 | u_int thisbit = bits & msb; |
984263bc MD |
1634 | csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ |
1635 | if (thisbit != lastbit) { | |
1636 | csr ^= SROMDOUT; EMIT; /* clock low; invert data */ | |
1637 | } else { | |
1638 | EMIT; | |
1639 | } | |
1640 | csr ^= SROMCLKON; EMIT; /* clock high; data valid */ | |
1641 | lastbit = thisbit; | |
1642 | } | |
1643 | csr ^= SROMCLKOFF; EMIT; | |
1644 | ||
1645 | for (data = 0, bits = 0; bits < 16; bits++) { | |
1646 | data <<= 1; | |
1647 | csr ^= SROMCLKON; EMIT; /* clock high; data valid */ | |
1648 | data |= TULIP_CSR_READ(sc, csr_srom_mii) & SROMDIN ? 1 : 0; | |
1649 | csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */ | |
1650 | } | |
1651 | sc->tulip_rombuf[idx*2] = data & 0xFF; | |
1652 | sc->tulip_rombuf[idx*2+1] = data >> 8; | |
1653 | csr = SROMSEL | SROMRD; EMIT; | |
1654 | csr = 0; EMIT; | |
1655 | } | |
1656 | tulip_srom_idle(sc); | |
1657 | } | |
79fe23de JS |
1658 | |
1659 | #define MII_EMIT do { \ | |
1660 | TULIP_CSR_WRITE(sc, csr_srom_mii, csr); \ | |
1661 | DELAY(1); \ | |
1662 | } while (0) | |
984263bc MD |
1663 | |
1664 | static void | |
79fe23de | 1665 | tulip_mii_writebits(tulip_softc_t *sc, u_int data, u_int bits) |
984263bc | 1666 | { |
79fe23de | 1667 | u_int csr, msb, lastbit; |
984263bc | 1668 | |
79fe23de JS |
1669 | msb = 1 << (bits - 1); |
1670 | csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); | |
1671 | lastbit = (csr & MII_DOUT) ? msb : 0; | |
984263bc MD |
1672 | csr |= MII_WR; MII_EMIT; /* clock low; assert write */ |
1673 | ||
1674 | for (; bits > 0; bits--, data <<= 1) { | |
1675 | const unsigned thisbit = data & msb; | |
1676 | if (thisbit != lastbit) { | |
1677 | csr ^= MII_DOUT; MII_EMIT; /* clock low; invert data */ | |
1678 | } | |
1679 | csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ | |
1680 | lastbit = thisbit; | |
1681 | csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ | |
1682 | } | |
1683 | } | |
1684 | ||
1685 | static void | |
79fe23de | 1686 | tulip_mii_turnaround(tulip_softc_t *sc, u_int cmd) |
984263bc | 1687 | { |
79fe23de JS |
1688 | u_int csr; |
1689 | ||
1690 | csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); | |
984263bc MD |
1691 | |
1692 | if (cmd == MII_WRCMD) { | |
1693 | csr |= MII_DOUT; MII_EMIT; /* clock low; change data */ | |
1694 | csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ | |
1695 | csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ | |
1696 | csr ^= MII_DOUT; MII_EMIT; /* clock low; change data */ | |
1697 | } else { | |
1698 | csr |= MII_RD; MII_EMIT; /* clock low; switch to read */ | |
1699 | } | |
1700 | csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ | |
1701 | csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ | |
1702 | } | |
1703 | ||
79fe23de JS |
1704 | static u_int |
1705 | tulip_mii_readbits(tulip_softc_t *sc) | |
984263bc | 1706 | { |
79fe23de JS |
1707 | u_int csr, data, idx; |
1708 | ||
1709 | csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); | |
984263bc MD |
1710 | |
1711 | for (idx = 0, data = 0; idx < 16; idx++) { | |
1712 | data <<= 1; /* this is NOOP on the first pass through */ | |
1713 | csr ^= MII_CLKON; MII_EMIT; /* clock high; data valid */ | |
1714 | if (TULIP_CSR_READ(sc, csr_srom_mii) & MII_DIN) | |
1715 | data |= 1; | |
1716 | csr ^= MII_CLKOFF; MII_EMIT; /* clock low; data not valid */ | |
1717 | } | |
1718 | csr ^= MII_RD; MII_EMIT; /* clock low; turn off read */ | |
1719 | ||
1720 | return data; | |
1721 | } | |
1722 | ||
79fe23de JS |
1723 | static u_int |
1724 | tulip_mii_readreg(tulip_softc_t *sc, u_int devaddr, u_int regno) | |
984263bc | 1725 | { |
79fe23de JS |
1726 | u_int csr; |
1727 | u_int data; | |
984263bc | 1728 | |
79fe23de | 1729 | csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); |
984263bc MD |
1730 | csr &= ~(MII_RD|MII_CLK); MII_EMIT; |
1731 | tulip_mii_writebits(sc, MII_PREAMBLE, 32); | |
1732 | tulip_mii_writebits(sc, MII_RDCMD, 8); | |
1733 | tulip_mii_writebits(sc, devaddr, 5); | |
1734 | tulip_mii_writebits(sc, regno, 5); | |
1735 | tulip_mii_turnaround(sc, MII_RDCMD); | |
1736 | ||
1737 | data = tulip_mii_readbits(sc); | |
984263bc MD |
1738 | return data; |
1739 | } | |
1740 | ||
1741 | static void | |
79fe23de | 1742 | tulip_mii_writereg(tulip_softc_t *sc, u_int devaddr, u_int regno, u_int data) |
984263bc | 1743 | { |
79fe23de JS |
1744 | u_int csr; |
1745 | ||
1746 | csr = TULIP_CSR_READ(sc, csr_srom_mii) & (MII_RD|MII_DOUT|MII_CLK); | |
984263bc MD |
1747 | csr &= ~(MII_RD|MII_CLK); MII_EMIT; |
1748 | tulip_mii_writebits(sc, MII_PREAMBLE, 32); | |
1749 | tulip_mii_writebits(sc, MII_WRCMD, 8); | |
1750 | tulip_mii_writebits(sc, devaddr, 5); | |
1751 | tulip_mii_writebits(sc, regno, 5); | |
1752 | tulip_mii_turnaround(sc, MII_WRCMD); | |
1753 | tulip_mii_writebits(sc, data, 16); | |
984263bc | 1754 | } |
79fe23de | 1755 | |
18261b0d | 1756 | #define tulip_mchash(mca) (ether_crc32_le(mca, 6) & 0x1FF) |
984263bc | 1757 | #define tulip_srom_crcok(databuf) ( \ |
18261b0d | 1758 | ((ether_crc32_le(databuf, 126) & 0xFFFFU) ^ 0xFFFFU) == \ |
984263bc | 1759 | ((databuf)[126] | ((databuf)[127] << 8))) |
5d2944c2 | 1760 | |
984263bc | 1761 | static void |
79fe23de | 1762 | tulip_identify_dec_nic(tulip_softc_t *sc) |
984263bc MD |
1763 | { |
1764 | strcpy(sc->tulip_boardid, "DEC "); | |
1765 | #define D0 4 | |
1766 | if (sc->tulip_chipid <= TULIP_21040) | |
1767 | return; | |
1768 | if (bcmp(sc->tulip_rombuf + 29, "DE500", 5) == 0 | |
1769 | || bcmp(sc->tulip_rombuf + 29, "DE450", 5) == 0) { | |
1770 | bcopy(sc->tulip_rombuf + 29, &sc->tulip_boardid[D0], 8); | |
1771 | sc->tulip_boardid[D0+8] = ' '; | |
1772 | } | |
1773 | #undef D0 | |
1774 | } | |
79fe23de | 1775 | |
984263bc | 1776 | static void |
79fe23de | 1777 | tulip_identify_znyx_nic(tulip_softc_t * const sc) |
984263bc | 1778 | { |
79fe23de | 1779 | u_int id = 0; |
984263bc MD |
1780 | strcpy(sc->tulip_boardid, "ZNYX ZX3XX "); |
1781 | if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) { | |
79fe23de | 1782 | u_int znyx_ptr; |
984263bc MD |
1783 | sc->tulip_boardid[8] = '4'; |
1784 | znyx_ptr = sc->tulip_rombuf[124] + 256 * sc->tulip_rombuf[125]; | |
1785 | if (znyx_ptr < 26 || znyx_ptr > 116) { | |
1786 | sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; | |
1787 | return; | |
1788 | } | |
1789 | /* ZX344 = 0010 .. 0013FF | |
1790 | */ | |
1791 | if (sc->tulip_rombuf[znyx_ptr] == 0x4A | |
1792 | && sc->tulip_rombuf[znyx_ptr + 1] == 0x52 | |
1793 | && sc->tulip_rombuf[znyx_ptr + 2] == 0x01) { | |
1794 | id = sc->tulip_rombuf[znyx_ptr + 5] + 256 * sc->tulip_rombuf[znyx_ptr + 4]; | |
1795 | if ((id >> 8) == (TULIP_ZNYX_ID_ZX342 >> 8)) { | |
1796 | sc->tulip_boardid[9] = '2'; | |
1797 | if (id == TULIP_ZNYX_ID_ZX342B) { | |
1798 | sc->tulip_boardid[10] = 'B'; | |
1799 | sc->tulip_boardid[11] = ' '; | |
1800 | } | |
1801 | sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; | |
1802 | } else if (id == TULIP_ZNYX_ID_ZX344) { | |
1803 | sc->tulip_boardid[10] = '4'; | |
1804 | sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; | |
1805 | } else if (id == TULIP_ZNYX_ID_ZX345) { | |
1806 | sc->tulip_boardid[9] = (sc->tulip_rombuf[19] > 1) ? '8' : '5'; | |
1807 | } else if (id == TULIP_ZNYX_ID_ZX346) { | |
1808 | sc->tulip_boardid[9] = '6'; | |
1809 | } else if (id == TULIP_ZNYX_ID_ZX351) { | |
1810 | sc->tulip_boardid[8] = '5'; | |
1811 | sc->tulip_boardid[9] = '1'; | |
1812 | } | |
1813 | } | |
1814 | if (id == 0) { | |
1815 | /* | |
1816 | * Assume it's a ZX342... | |
1817 | */ | |
1818 | sc->tulip_boardsw = &tulip_21140_znyx_zx34x_boardsw; | |
1819 | } | |
1820 | return; | |
1821 | } | |
1822 | sc->tulip_boardid[8] = '1'; | |
1823 | if (sc->tulip_chipid == TULIP_21041) { | |
1824 | sc->tulip_boardid[10] = '1'; | |
1825 | return; | |
1826 | } | |
1827 | if (sc->tulip_rombuf[32] == 0x4A && sc->tulip_rombuf[33] == 0x52) { | |
1828 | id = sc->tulip_rombuf[37] + 256 * sc->tulip_rombuf[36]; | |
1829 | if (id == TULIP_ZNYX_ID_ZX312T) { | |
1830 | sc->tulip_boardid[9] = '2'; | |
1831 | sc->tulip_boardid[10] = 'T'; | |
1832 | sc->tulip_boardid[11] = ' '; | |
1833 | sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; | |
1834 | } else if (id == TULIP_ZNYX_ID_ZX314_INTA) { | |
1835 | sc->tulip_boardid[9] = '4'; | |
1836 | sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; | |
1837 | sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; | |
1838 | } else if (id == TULIP_ZNYX_ID_ZX314) { | |
1839 | sc->tulip_boardid[9] = '4'; | |
1840 | sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; | |
1841 | sc->tulip_features |= TULIP_HAVE_BASEROM; | |
1842 | } else if (id == TULIP_ZNYX_ID_ZX315_INTA) { | |
1843 | sc->tulip_boardid[9] = '5'; | |
1844 | sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; | |
1845 | } else if (id == TULIP_ZNYX_ID_ZX315) { | |
1846 | sc->tulip_boardid[9] = '5'; | |
1847 | sc->tulip_features |= TULIP_HAVE_BASEROM; | |
1848 | } else { | |
1849 | id = 0; | |
1850 | } | |
1851 | } | |
1852 | if (id == 0) { | |
5d2944c2 | 1853 | if ((sc->arpcom.ac_enaddr[3] & ~3) == 0xF0 && (sc->arpcom.ac_enaddr[5] & 2) == 0) { |
984263bc MD |
1854 | sc->tulip_boardid[9] = '4'; |
1855 | sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; | |
1856 | sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; | |
5d2944c2 | 1857 | } else if ((sc->arpcom.ac_enaddr[3] & ~3) == 0xF4 && (sc->arpcom.ac_enaddr[5] & 1) == 0) { |
984263bc MD |
1858 | sc->tulip_boardid[9] = '5'; |
1859 | sc->tulip_boardsw = &tulip_21040_boardsw; | |
1860 | sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; | |
5d2944c2 | 1861 | } else if ((sc->arpcom.ac_enaddr[3] & ~3) == 0xEC) { |
984263bc MD |
1862 | sc->tulip_boardid[9] = '2'; |
1863 | sc->tulip_boardsw = &tulip_21040_boardsw; | |
1864 | } | |
1865 | } | |
1866 | } | |
79fe23de | 1867 | |
984263bc | 1868 | static void |
79fe23de | 1869 | tulip_identify_smc_nic(tulip_softc_t * const sc) |
984263bc | 1870 | { |
79fe23de | 1871 | uint32_t id1, id2, ei; |
984263bc MD |
1872 | int auibnc = 0, utp = 0; |
1873 | char *cp; | |
1874 | ||
1875 | strcpy(sc->tulip_boardid, "SMC "); | |
1876 | if (sc->tulip_chipid == TULIP_21041) | |
1877 | return; | |
1878 | if (sc->tulip_chipid != TULIP_21040) { | |
1879 | if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) { | |
1880 | strcpy(&sc->tulip_boardid[4], "9332DST "); | |
1881 | sc->tulip_boardsw = &tulip_21140_smc9332_boardsw; | |
1882 | } else if (sc->tulip_features & (TULIP_HAVE_BASEROM|TULIP_HAVE_SLAVEDROM)) { | |
1883 | strcpy(&sc->tulip_boardid[4], "9334BDT "); | |
1884 | } else { | |
1885 | strcpy(&sc->tulip_boardid[4], "9332BDT "); | |
1886 | } | |
1887 | return; | |
1888 | } | |
1889 | id1 = sc->tulip_rombuf[0x60] | (sc->tulip_rombuf[0x61] << 8); | |
1890 | id2 = sc->tulip_rombuf[0x62] | (sc->tulip_rombuf[0x63] << 8); | |
1891 | ei = sc->tulip_rombuf[0x66] | (sc->tulip_rombuf[0x67] << 8); | |
1892 | ||
1893 | strcpy(&sc->tulip_boardid[4], "8432"); | |
1894 | cp = &sc->tulip_boardid[8]; | |
1895 | if ((id1 & 1) == 0) | |
1896 | *cp++ = 'B', auibnc = 1; | |
1897 | if ((id1 & 0xFF) > 0x32) | |
1898 | *cp++ = 'T', utp = 1; | |
1899 | if ((id1 & 0x4000) == 0) | |
1900 | *cp++ = 'A', auibnc = 1; | |
1901 | if (id2 == 0x15) { | |
1902 | sc->tulip_boardid[7] = '4'; | |
1903 | *cp++ = '-'; | |
1904 | *cp++ = 'C'; | |
1905 | *cp++ = 'H'; | |
1906 | *cp++ = (ei ? '2' : '1'); | |
1907 | } | |
1908 | *cp++ = ' '; | |
1909 | *cp = '\0'; | |
1910 | if (utp && !auibnc) | |
1911 | sc->tulip_boardsw = &tulip_21040_10baset_only_boardsw; | |
1912 | else if (!utp && auibnc) | |
1913 | sc->tulip_boardsw = &tulip_21040_auibnc_only_boardsw; | |
1914 | } | |
79fe23de | 1915 | |
984263bc | 1916 | static void |
79fe23de | 1917 | tulip_identify_cogent_nic(tulip_softc_t * const sc) |
984263bc MD |
1918 | { |
1919 | strcpy(sc->tulip_boardid, "Cogent "); | |
1920 | if (sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) { | |
1921 | if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100TX_ID) { | |
1922 | strcat(sc->tulip_boardid, "EM100TX "); | |
1923 | sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; | |
1924 | #if defined(TULIP_COGENT_EM110TX_ID) | |
1925 | } else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM110TX_ID) { | |
1926 | strcat(sc->tulip_boardid, "EM110TX "); | |
1927 | sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; | |
1928 | #endif | |
1929 | } else if (sc->tulip_rombuf[32] == TULIP_COGENT_EM100FX_ID) { | |
1930 | strcat(sc->tulip_boardid, "EM100FX "); | |
1931 | sc->tulip_boardsw = &tulip_21140_cogent_em100_boardsw; | |
1932 | } | |
1933 | /* | |
1934 | * Magic number (0x24001109U) is the SubVendor (0x2400) and | |
1935 | * SubDevId (0x1109) for the ANA6944TX (EM440TX). | |
1936 | */ | |
79fe23de | 1937 | if (*(uint32_t *) sc->tulip_rombuf == 0x24001109U |
984263bc MD |
1938 | && (sc->tulip_features & TULIP_HAVE_BASEROM)) { |
1939 | /* | |
1940 | * Cogent (Adaptec) is still mapping all INTs to INTA of | |
1941 | * first 21140. Dumb! Dumb! | |
1942 | */ | |
1943 | strcat(sc->tulip_boardid, "EM440TX "); | |
1944 | sc->tulip_features |= TULIP_HAVE_SHAREDINTR; | |
1945 | } | |
1946 | } else if (sc->tulip_chipid == TULIP_21040) { | |
1947 | sc->tulip_features |= TULIP_HAVE_SHAREDINTR|TULIP_HAVE_BASEROM; | |
1948 | } | |
1949 | } | |
79fe23de | 1950 | |
984263bc | 1951 | static void |
79fe23de | 1952 | tulip_identify_accton_nic(tulip_softc_t * const sc) |
984263bc MD |
1953 | { |
1954 | strcpy(sc->tulip_boardid, "ACCTON "); | |
1955 | switch (sc->tulip_chipid) { | |
1956 | case TULIP_21140A: | |
1957 | strcat(sc->tulip_boardid, "EN1207 "); | |
1958 | if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) | |
1959 | sc->tulip_boardsw = &tulip_21140_accton_boardsw; | |
1960 | break; | |
1961 | case TULIP_21140: | |
1962 | strcat(sc->tulip_boardid, "EN1207TX "); | |
1963 | if (sc->tulip_boardsw != &tulip_2114x_isv_boardsw) | |
1964 | sc->tulip_boardsw = &tulip_21140_eb_boardsw; | |
1965 | break; | |
1966 | case TULIP_21040: | |
1967 | strcat(sc->tulip_boardid, "EN1203 "); | |
1968 | sc->tulip_boardsw = &tulip_21040_boardsw; | |
1969 | break; | |
1970 | case TULIP_21041: | |
1971 | strcat(sc->tulip_boardid, "EN1203 "); | |
1972 | sc->tulip_boardsw = &tulip_21041_boardsw; | |
1973 | break; | |
1974 | default: | |
1975 | sc->tulip_boardsw = &tulip_2114x_isv_boardsw; | |
1976 | break; | |
1977 | } | |
1978 | } | |
79fe23de | 1979 | |
984263bc | 1980 | static void |
79fe23de | 1981 | tulip_identify_asante_nic(tulip_softc_t * const sc) |
984263bc MD |
1982 | { |
1983 | strcpy(sc->tulip_boardid, "Asante "); | |
1984 | if ((sc->tulip_chipid == TULIP_21140 || sc->tulip_chipid == TULIP_21140A) | |
1985 | && sc->tulip_boardsw != &tulip_2114x_isv_boardsw) { | |
1986 | tulip_media_info_t *mi = sc->tulip_mediainfo; | |
1987 | int idx; | |
1988 | /* | |
1989 | * The Asante Fast Ethernet doesn't always ship with a valid | |
1990 | * new format SROM. So if isn't in the new format, we cheat | |
1991 | * set it up as if we had. | |
1992 | */ | |
1993 | ||
1994 | sc->tulip_gpinit = TULIP_GP_ASANTE_PINS; | |
1995 | sc->tulip_gpdata = 0; | |
1996 | ||
1997 | TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PINS|TULIP_GP_PINSET); | |
1998 | TULIP_CSR_WRITE(sc, csr_gp, TULIP_GP_ASANTE_PHYRESET); | |
1999 | DELAY(100); | |
2000 | TULIP_CSR_WRITE(sc, csr_gp, 0); | |
2001 | ||
2002 | mi->mi_type = TULIP_MEDIAINFO_MII; | |
2003 | mi->mi_gpr_length = 0; | |
2004 | mi->mi_gpr_offset = 0; | |
2005 | mi->mi_reset_length = 0; | |
fc6d0222 | 2006 | mi->mi_reset_offset = 0; |
984263bc MD |
2007 | |
2008 | mi->mi_phyaddr = TULIP_MII_NOPHY; | |
2009 | for (idx = 20; idx > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx--) { | |
2010 | DELAY(10000); | |
2011 | mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, 0); | |
2012 | } | |
2013 | if (mi->mi_phyaddr == TULIP_MII_NOPHY) { | |
5d2944c2 | 2014 | if_printf(&sc->arpcom.ac_if, "can't find phy 0\n"); |
984263bc MD |
2015 | return; |
2016 | } | |
2017 | ||
2018 | sc->tulip_features |= TULIP_HAVE_MII; | |
2019 | mi->mi_capabilities = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD; | |
2020 | mi->mi_advertisement = PHYSTS_10BASET|PHYSTS_10BASET_FD|PHYSTS_100BASETX|PHYSTS_100BASETX_FD; | |
2021 | mi->mi_full_duplex = PHYSTS_10BASET_FD|PHYSTS_100BASETX_FD; | |
2022 | mi->mi_tx_threshold = PHYSTS_10BASET|PHYSTS_10BASET_FD; | |
2023 | TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); | |
2024 | TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); | |
2025 | TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); | |
2026 | TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); | |
2027 | TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); | |
2028 | mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | | |
2029 | tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); | |
2030 | ||
2031 | sc->tulip_boardsw = &tulip_2114x_isv_boardsw; | |
2032 | } | |
2033 | } | |
79fe23de | 2034 | |
984263bc | 2035 | static void |
79fe23de | 2036 | tulip_identify_compex_nic(tulip_softc_t *sc) |
984263bc MD |
2037 | { |
2038 | strcpy(sc->tulip_boardid, "COMPEX "); | |
2039 | if (sc->tulip_chipid == TULIP_21140A) { | |
2040 | int root_unit; | |
2041 | tulip_softc_t *root_sc = NULL; | |
2042 | ||
2043 | strcat(sc->tulip_boardid, "400TX/PCI "); | |
2044 | /* | |
2045 | * All 4 chips on these boards share an interrupt. This code | |
2046 | * copied from tulip_read_macaddr. | |
2047 | */ | |
2048 | sc->tulip_features |= TULIP_HAVE_SHAREDINTR; | |
5d2944c2 | 2049 | for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) { |
984263bc MD |
2050 | root_sc = tulips[root_unit]; |
2051 | if (root_sc == NULL | |
2052 | || !(root_sc->tulip_features & TULIP_HAVE_SLAVEDINTR)) | |
2053 | break; | |
2054 | root_sc = NULL; | |
2055 | } | |
2056 | if (root_sc != NULL | |
2057 | && root_sc->tulip_chipid == sc->tulip_chipid | |
2058 | && root_sc->tulip_pci_busno == sc->tulip_pci_busno) { | |
2059 | sc->tulip_features |= TULIP_HAVE_SLAVEDINTR; | |
2060 | sc->tulip_slaves = root_sc->tulip_slaves; | |
2061 | root_sc->tulip_slaves = sc; | |
2062 | } else if(sc->tulip_features & TULIP_HAVE_SLAVEDINTR) { | |
5d2944c2 | 2063 | if_printf(&sc->arpcom.ac_if, "can't find master device for interrupts"); |
984263bc MD |
2064 | } |
2065 | } else { | |
2066 | strcat(sc->tulip_boardid, "unknown "); | |
2067 | } | |
2068 | /* sc->tulip_boardsw = &tulip_21140_eb_boardsw; */ | |
2069 | return; | |
2070 | } | |
5d2944c2 | 2071 | |
984263bc | 2072 | static int |
79fe23de | 2073 | tulip_srom_decode(tulip_softc_t *sc) |
984263bc | 2074 | { |
79fe23de | 2075 | u_int idx1, idx2, idx3; |
984263bc MD |
2076 | |
2077 | const tulip_srom_header_t *shp = (const tulip_srom_header_t *) &sc->tulip_rombuf[0]; | |
2078 | const tulip_srom_adapter_info_t *saip = (const tulip_srom_adapter_info_t *) (shp + 1); | |
2079 | tulip_srom_media_t srom_media; | |
2080 | tulip_media_info_t *mi = sc->tulip_mediainfo; | |
79fe23de JS |
2081 | const uint8_t *dp; |
2082 | uint32_t leaf_offset, blocks, data; | |
984263bc MD |
2083 | |
2084 | for (idx1 = 0; idx1 < shp->sh_adapter_count; idx1++, saip++) { | |
2085 | if (shp->sh_adapter_count == 1) | |
2086 | break; | |
2087 | if (saip->sai_device == sc->tulip_pci_devno) | |
2088 | break; | |
2089 | } | |
2090 | /* | |
2091 | * Didn't find the right media block for this card. | |
2092 | */ | |
2093 | if (idx1 == shp->sh_adapter_count) | |
2094 | return 0; | |
2095 | ||
2096 | /* | |
2097 | * Save the hardware address. | |
2098 | */ | |
5d2944c2 | 2099 | bcopy(shp->sh_ieee802_address, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); |
984263bc MD |
2100 | /* |
2101 | * If this is a multiple port card, add the adapter index to the last | |
2102 | * byte of the hardware address. (if it isn't multiport, adding 0 | |
2103 | * won't hurt. | |
2104 | */ | |
5d2944c2 | 2105 | sc->arpcom.ac_enaddr[5] += idx1; |
984263bc MD |
2106 | |
2107 | leaf_offset = saip->sai_leaf_offset_lowbyte | |
2108 | + saip->sai_leaf_offset_highbyte * 256; | |
2109 | dp = sc->tulip_rombuf + leaf_offset; | |
2110 | ||
2111 | sc->tulip_conntype = (tulip_srom_connection_t) (dp[0] + dp[1] * 256); dp += 2; | |
2112 | ||
2113 | for (idx2 = 0;; idx2++) { | |
2114 | if (tulip_srom_conninfo[idx2].sc_type == sc->tulip_conntype | |
2115 | || tulip_srom_conninfo[idx2].sc_type == TULIP_SROM_CONNTYPE_NOT_USED) | |
2116 | break; | |
2117 | } | |
2118 | sc->tulip_connidx = idx2; | |
2119 | ||
2120 | if (sc->tulip_chipid == TULIP_21041) { | |
2121 | blocks = *dp++; | |
2122 | for (idx2 = 0; idx2 < blocks; idx2++) { | |
2123 | tulip_media_t media; | |
2124 | data = *dp++; | |
2125 | srom_media = (tulip_srom_media_t) (data & 0x3F); | |
2126 | for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { | |
2127 | if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) | |
2128 | break; | |
2129 | } | |
2130 | media = tulip_srom_mediums[idx3].sm_type; | |
2131 | if (media != TULIP_MEDIA_UNKNOWN) { | |
2132 | if (data & TULIP_SROM_21041_EXTENDED) { | |
2133 | mi->mi_type = TULIP_MEDIAINFO_SIA; | |
2134 | sc->tulip_mediums[media] = mi; | |
2135 | mi->mi_sia_connectivity = dp[0] + dp[1] * 256; | |
2136 | mi->mi_sia_tx_rx = dp[2] + dp[3] * 256; | |
2137 | mi->mi_sia_general = dp[4] + dp[5] * 256; | |
2138 | mi++; | |
2139 | } else { | |
2140 | switch (media) { | |
2141 | case TULIP_MEDIA_BNC: { | |
2142 | TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); | |
2143 | mi++; | |
2144 | break; | |
2145 | } | |
2146 | case TULIP_MEDIA_AUI: { | |
2147 | TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); | |
2148 | mi++; | |
2149 | break; | |
2150 | } | |
2151 | case TULIP_MEDIA_10BASET: { | |
2152 | TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); | |
2153 | mi++; | |
2154 | break; | |
2155 | } | |
2156 | case TULIP_MEDIA_10BASET_FD: { | |
2157 | TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); | |
2158 | mi++; | |
2159 | break; | |
2160 | } | |
2161 | default: { | |
2162 | break; | |
2163 | } | |
2164 | } | |
2165 | } | |
2166 | } | |
2167 | if (data & TULIP_SROM_21041_EXTENDED) | |
2168 | dp += 6; | |
2169 | } | |
2170 | #ifdef notdef | |
2171 | if (blocks == 0) { | |
2172 | TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, BNC); mi++; | |
2173 | TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, AUI); mi++; | |
2174 | TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET); mi++; | |
2175 | TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21041, 10BASET_FD); mi++; | |
2176 | } | |
2177 | #endif | |
2178 | } else { | |
2179 | unsigned length, type; | |
2180 | tulip_media_t gp_media = TULIP_MEDIA_UNKNOWN; | |
2181 | if (sc->tulip_features & TULIP_HAVE_GPR) | |
2182 | sc->tulip_gpinit = *dp++; | |
2183 | blocks = *dp++; | |
2184 | for (idx2 = 0; idx2 < blocks; idx2++) { | |
79fe23de | 2185 | const uint8_t *ep; |
984263bc MD |
2186 | if ((*dp & 0x80) == 0) { |
2187 | length = 4; | |
2188 | type = 0; | |
2189 | } else { | |
2190 | length = (*dp++ & 0x7f) - 1; | |
2191 | type = *dp++ & 0x3f; | |
2192 | } | |
2193 | ep = dp + length; | |
2194 | switch (type & 0x3f) { | |
2195 | case 0: { /* 21140[A] GPR block */ | |
2196 | tulip_media_t media; | |
2197 | srom_media = (tulip_srom_media_t)(dp[0] & 0x3f); | |
2198 | for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { | |
2199 | if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) | |
2200 | break; | |
2201 | } | |
2202 | media = tulip_srom_mediums[idx3].sm_type; | |
2203 | if (media == TULIP_MEDIA_UNKNOWN) | |
2204 | break; | |
2205 | mi->mi_type = TULIP_MEDIAINFO_GPR; | |
2206 | sc->tulip_mediums[media] = mi; | |
2207 | mi->mi_gpdata = dp[1]; | |
2208 | if (media > gp_media && !TULIP_IS_MEDIA_FD(media)) { | |
2209 | sc->tulip_gpdata = mi->mi_gpdata; | |
2210 | gp_media = media; | |
2211 | } | |
2212 | data = dp[2] + dp[3] * 256; | |
2213 | mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data); | |
2214 | if (data & TULIP_SROM_2114X_NOINDICATOR) { | |
2215 | mi->mi_actmask = 0; | |
2216 | } else { | |
2217 | #if 0 | |
2218 | mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0; | |
2219 | #endif | |
2220 | mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data); | |
2221 | mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask; | |
2222 | } | |
2223 | mi++; | |
2224 | break; | |
2225 | } | |
2226 | case 1: { /* 21140[A] MII block */ | |
79fe23de | 2227 | const u_int phyno = *dp++; |
984263bc MD |
2228 | mi->mi_type = TULIP_MEDIAINFO_MII; |
2229 | mi->mi_gpr_length = *dp++; | |
2230 | mi->mi_gpr_offset = dp - sc->tulip_rombuf; | |
2231 | dp += mi->mi_gpr_length; | |
2232 | mi->mi_reset_length = *dp++; | |
2233 | mi->mi_reset_offset = dp - sc->tulip_rombuf; | |
2234 | dp += mi->mi_reset_length; | |
2235 | ||
2236 | /* | |
2237 | * Before we probe for a PHY, use the GPR information | |
2238 | * to select it. If we don't, it may be inaccessible. | |
2239 | */ | |
2240 | TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_gpinit|TULIP_GP_PINSET); | |
2241 | for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++) { | |
2242 | DELAY(10); | |
2243 | TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_reset_offset + idx3]); | |
2244 | } | |
2245 | sc->tulip_phyaddr = mi->mi_phyaddr; | |
2246 | for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++) { | |
2247 | DELAY(10); | |
2248 | TULIP_CSR_WRITE(sc, csr_gp, sc->tulip_rombuf[mi->mi_gpr_offset + idx3]); | |
2249 | } | |
2250 | ||
2251 | /* | |
2252 | * At least write something! | |
2253 | */ | |
2254 | if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0) | |
2255 | TULIP_CSR_WRITE(sc, csr_gp, 0); | |
2256 | ||
2257 | mi->mi_phyaddr = TULIP_MII_NOPHY; | |
2258 | for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) { | |
2259 | DELAY(10000); | |
2260 | mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno); | |
2261 | } | |
46a77a85 | 2262 | if (mi->mi_phyaddr == TULIP_MII_NOPHY) |
984263bc | 2263 | break; |
984263bc MD |
2264 | sc->tulip_features |= TULIP_HAVE_MII; |
2265 | mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2; | |
2266 | mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2; | |
2267 | mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2; | |
2268 | mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2; | |
2269 | TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); | |
2270 | TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); | |
2271 | TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); | |
2272 | TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); | |
2273 | TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); | |
2274 | mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | | |
2275 | tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); | |
2276 | mi++; | |
2277 | break; | |
2278 | } | |
2279 | case 2: { /* 2114[23] SIA block */ | |
2280 | tulip_media_t media; | |
2281 | srom_media = (tulip_srom_media_t)(dp[0] & 0x3f); | |
2282 | for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { | |
2283 | if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) | |
2284 | break; | |
2285 | } | |
2286 | media = tulip_srom_mediums[idx3].sm_type; | |
2287 | if (media == TULIP_MEDIA_UNKNOWN) | |
2288 | break; | |
2289 | mi->mi_type = TULIP_MEDIAINFO_SIA; | |
2290 | sc->tulip_mediums[media] = mi; | |
2291 | if (dp[0] & 0x40) { | |
2292 | mi->mi_sia_connectivity = dp[1] + dp[2] * 256; | |
2293 | mi->mi_sia_tx_rx = dp[3] + dp[4] * 256; | |
2294 | mi->mi_sia_general = dp[5] + dp[6] * 256; | |
2295 | dp += 6; | |
2296 | } else { | |
2297 | switch (media) { | |
2298 | case TULIP_MEDIA_BNC: { | |
2299 | TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, BNC); | |
2300 | break; | |
2301 | } | |
2302 | case TULIP_MEDIA_AUI: { | |
2303 | TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, AUI); | |
2304 | break; | |
2305 | } | |
2306 | case TULIP_MEDIA_10BASET: { | |
2307 | TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET); | |
2308 | sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; | |
2309 | break; | |
2310 | } | |
2311 | case TULIP_MEDIA_10BASET_FD: { | |
2312 | TULIP_MEDIAINFO_SIA_INIT(sc, mi, 21142, 10BASET_FD); | |
2313 | sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; | |
2314 | break; | |
2315 | } | |
2316 | default: { | |
2317 | goto bad_media; | |
2318 | } | |
2319 | } | |
2320 | } | |
2321 | mi->mi_sia_gp_control = (dp[1] + dp[2] * 256) << 16; | |
2322 | mi->mi_sia_gp_data = (dp[3] + dp[4] * 256) << 16; | |
2323 | mi++; | |
2324 | bad_media: | |
2325 | break; | |
2326 | } | |
2327 | case 3: { /* 2114[23] MII PHY block */ | |
79fe23de JS |
2328 | const u_int phyno = *dp++; |
2329 | const uint8_t *dp0; | |
984263bc MD |
2330 | mi->mi_type = TULIP_MEDIAINFO_MII; |
2331 | mi->mi_gpr_length = *dp++; | |
2332 | mi->mi_gpr_offset = dp - sc->tulip_rombuf; | |
2333 | dp += 2 * mi->mi_gpr_length; | |
2334 | mi->mi_reset_length = *dp++; | |
2335 | mi->mi_reset_offset = dp - sc->tulip_rombuf; | |
2336 | dp += 2 * mi->mi_reset_length; | |
2337 | ||
2338 | dp0 = &sc->tulip_rombuf[mi->mi_reset_offset]; | |
2339 | for (idx3 = 0; idx3 < mi->mi_reset_length; idx3++, dp0 += 2) { | |
2340 | DELAY(10); | |
2341 | TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16); | |
2342 | } | |
2343 | sc->tulip_phyaddr = mi->mi_phyaddr; | |
2344 | dp0 = &sc->tulip_rombuf[mi->mi_gpr_offset]; | |
2345 | for (idx3 = 0; idx3 < mi->mi_gpr_length; idx3++, dp0 += 2) { | |
2346 | DELAY(10); | |
2347 | TULIP_CSR_WRITE(sc, csr_sia_general, (dp0[0] + 256 * dp0[1]) << 16); | |
2348 | } | |
2349 | ||
2350 | if (mi->mi_reset_length == 0 && mi->mi_gpr_length == 0) | |
2351 | TULIP_CSR_WRITE(sc, csr_sia_general, 0); | |
2352 | ||
2353 | mi->mi_phyaddr = TULIP_MII_NOPHY; | |
2354 | for (idx3 = 20; idx3 > 0 && mi->mi_phyaddr == TULIP_MII_NOPHY; idx3--) { | |
2355 | DELAY(10000); | |
2356 | mi->mi_phyaddr = tulip_mii_get_phyaddr(sc, phyno); | |
2357 | } | |
46a77a85 | 2358 | if (mi->mi_phyaddr == TULIP_MII_NOPHY) |
984263bc | 2359 | break; |
984263bc MD |
2360 | sc->tulip_features |= TULIP_HAVE_MII; |
2361 | mi->mi_capabilities = dp[0] + dp[1] * 256; dp += 2; | |
2362 | mi->mi_advertisement = dp[0] + dp[1] * 256; dp += 2; | |
2363 | mi->mi_full_duplex = dp[0] + dp[1] * 256; dp += 2; | |
2364 | mi->mi_tx_threshold = dp[0] + dp[1] * 256; dp += 2; | |
2365 | mi->mi_mii_interrupt = dp[0] + dp[1] * 256; dp += 2; | |
2366 | TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX_FD); | |
2367 | TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASETX); | |
2368 | TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 100BASET4); | |
2369 | TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET_FD); | |
2370 | TULIP_MEDIAINFO_ADD_CAPABILITY(sc, mi, 10BASET); | |
2371 | mi->mi_phyid = (tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDLOW) << 16) | | |
2372 | tulip_mii_readreg(sc, mi->mi_phyaddr, PHYREG_IDHIGH); | |
2373 | mi++; | |
2374 | break; | |
2375 | } | |
2376 | case 4: { /* 21143 SYM block */ | |
2377 | tulip_media_t media; | |
2378 | srom_media = (tulip_srom_media_t) dp[0]; | |
2379 | for (idx3 = 0; tulip_srom_mediums[idx3].sm_type != TULIP_MEDIA_UNKNOWN; idx3++) { | |
2380 | if (tulip_srom_mediums[idx3].sm_srom_type == srom_media) | |
2381 | break; | |
2382 | } | |
2383 | media = tulip_srom_mediums[idx3].sm_type; | |
2384 | if (media == TULIP_MEDIA_UNKNOWN) | |
2385 | break; | |
2386 | mi->mi_type = TULIP_MEDIAINFO_SYM; | |
2387 | sc->tulip_mediums[media] = mi; | |
2388 | mi->mi_gpcontrol = (dp[1] + dp[2] * 256) << 16; | |
2389 | mi->mi_gpdata = (dp[3] + dp[4] * 256) << 16; | |
2390 | data = dp[5] + dp[6] * 256; | |
2391 | mi->mi_cmdmode = TULIP_SROM_2114X_CMDBITS(data); | |
2392 | if (data & TULIP_SROM_2114X_NOINDICATOR) { | |
2393 | mi->mi_actmask = 0; | |
2394 | } else { | |
2395 | mi->mi_default = (data & TULIP_SROM_2114X_DEFAULT) != 0; | |
2396 | mi->mi_actmask = TULIP_SROM_2114X_BITPOS(data); | |
2397 | mi->mi_actdata = (data & TULIP_SROM_2114X_POLARITY) ? 0 : mi->mi_actmask; | |
2398 | } | |
2399 | if (TULIP_IS_MEDIA_TP(media)) | |
2400 | sc->tulip_intrmask |= TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL; | |
2401 | mi++; | |
2402 | break; | |
2403 | } | |
2404 | #if 0 | |
2405 | case 5: { /* 21143 Reset block */ | |
2406 | mi->mi_type = TULIP_MEDIAINFO_RESET; | |
2407 | mi->mi_reset_length = *dp++; | |
2408 | mi->mi_reset_offset = dp - sc->tulip_rombuf; | |
2409 | dp += 2 * mi->mi_reset_length; | |
2410 | mi++; | |
2411 | break; | |
2412 | } | |
2413 | #endif | |
2414 | default: { | |
2415 | } | |
2416 | } | |
2417 | dp = ep; | |
2418 | } | |
2419 | } | |
2420 | return mi - sc->tulip_mediainfo; | |
2421 | } | |
5d2944c2 | 2422 | |
984263bc MD |
2423 | static const struct { |
2424 | void (*vendor_identify_nic)(tulip_softc_t * const sc); | |
2425 | unsigned char vendor_oui[3]; | |
2426 | } tulip_vendors[] = { | |
2427 | { tulip_identify_dec_nic, { 0x08, 0x00, 0x2B } }, | |
2428 | { tulip_identify_dec_nic, { 0x00, 0x00, 0xF8 } }, | |
2429 | { tulip_identify_smc_nic, { 0x00, 0x00, 0xC0 } }, | |
2430 | { tulip_identify_smc_nic, { 0x00, 0xE0, 0x29 } }, | |
2431 | { tulip_identify_znyx_nic, { 0x00, 0xC0, 0x95 } }, | |
2432 | { tulip_identify_cogent_nic, { 0x00, 0x00, 0x92 } }, | |
2433 | { tulip_identify_asante_nic, { 0x00, 0x00, 0x94 } }, | |
2434 | { tulip_identify_cogent_nic, { 0x00, 0x00, 0xD1 } }, | |
2435 | { tulip_identify_accton_nic, { 0x00, 0x00, 0xE8 } }, | |
2436 | { tulip_identify_compex_nic, { 0x00, 0x80, 0x48 } }, | |
2437 | { NULL } | |
2438 | }; | |
2439 | ||
2440 | /* | |
2441 | * This deals with the vagaries of the address roms and the | |
2442 | * brain-deadness that various vendors commit in using them. | |
2443 | */ | |
2444 | static int | |
79fe23de | 2445 | tulip_read_macaddr(tulip_softc_t *sc) |
984263bc | 2446 | { |
79fe23de JS |
2447 | u_int cksum, rom_cksum, idx; |
2448 | uint32_t csr; | |
984263bc MD |
2449 | unsigned char tmpbuf[8]; |
2450 | static const u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA }; | |
2451 | ||
2452 | sc->tulip_connidx = TULIP_SROM_LASTCONNIDX; | |
2453 | ||
2454 | if (sc->tulip_chipid == TULIP_21040) { | |
2455 | TULIP_CSR_WRITE(sc, csr_enetrom, 1); | |
2456 | for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) { | |
2457 | int cnt = 0; | |
2458 | while (((csr = TULIP_CSR_READ(sc, csr_enetrom)) & 0x80000000L) && cnt < 10000) | |
2459 | cnt++; | |
2460 | sc->tulip_rombuf[idx] = csr & 0xFF; | |
2461 | } | |
2462 | sc->tulip_boardsw = &tulip_21040_boardsw; | |
2463 | } else { | |
2464 | if (sc->tulip_chipid == TULIP_21041) { | |
2465 | /* | |
2466 | * Thankfully all 21041's act the same. | |
2467 | */ | |
2468 | sc->tulip_boardsw = &tulip_21041_boardsw; | |
2469 | } else { | |
2470 | /* | |
2471 | * Assume all 21140 board are compatible with the | |
2472 | * DEC 10/100 evaluation board. Not really valid but | |
2473 | * it's the best we can do until every one switches to | |
2474 | * the new SROM format. | |
2475 | */ | |
2476 | ||
2477 | sc->tulip_boardsw = &tulip_21140_eb_boardsw; | |
2478 | } | |
2479 | tulip_srom_read(sc); | |
2480 | if (tulip_srom_crcok(sc->tulip_rombuf)) { | |
2481 | /* | |
2482 | * SROM CRC is valid therefore it must be in the | |
2483 | * new format. | |
2484 | */ | |
2485 | sc->tulip_features |= TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM; | |
2486 | } else if (sc->tulip_rombuf[126] == 0xff && sc->tulip_rombuf[127] == 0xFF) { | |
2487 | /* | |
2488 | * No checksum is present. See if the SROM id checks out; | |
2489 | * the first 18 bytes should be 0 followed by a 1 followed | |
2490 | * by the number of adapters (which we don't deal with yet). | |
2491 | */ | |
2492 | for (idx = 0; idx < 18; idx++) { | |
2493 | if (sc->tulip_rombuf[idx] != 0) | |
2494 | break; | |
2495 | } | |
2496 | if (idx == 18 && sc->tulip_rombuf[18] == 1 && sc->tulip_rombuf[19] != 0) | |
2497 | sc->tulip_features |= TULIP_HAVE_ISVSROM; | |
2498 | } else if (sc->tulip_chipid >= TULIP_21142) { | |
2499 | sc->tulip_features |= TULIP_HAVE_ISVSROM; | |
2500 | sc->tulip_boardsw = &tulip_2114x_isv_boardsw; | |
2501 | } | |
2502 | if ((sc->tulip_features & TULIP_HAVE_ISVSROM) && tulip_srom_decode(sc)) { | |
2503 | if (sc->tulip_chipid != TULIP_21041) | |
2504 | sc->tulip_boardsw = &tulip_2114x_isv_boardsw; | |
2505 | ||
2506 | /* | |
2507 | * If the SROM specifies more than one adapter, tag this as a | |
2508 | * BASE rom. | |
2509 | */ | |
2510 | if (sc->tulip_rombuf[19] > 1) | |
2511 | sc->tulip_features |= TULIP_HAVE_BASEROM; | |
2512 | if (sc->tulip_boardsw == NULL) | |
2513 | return -6; | |
2514 | goto check_oui; | |
2515 | } | |
2516 | } | |
2517 | ||
2518 | ||
2519 | if (bcmp(&sc->tulip_rombuf[0], &sc->tulip_rombuf[16], 8) != 0) { | |
2520 | /* | |
2521 | * Some folks don't use the standard ethernet rom format | |
2522 | * but instead just put the address in the first 6 bytes | |
2523 | * of the rom and let the rest be all 0xffs. (Can we say | |
2524 | * ZNYX?) (well sometimes they put in a checksum so we'll | |
2525 | * start at 8). | |
2526 | */ | |
2527 | for (idx = 8; idx < 32; idx++) { | |
2528 | if (sc->tulip_rombuf[idx] != 0xFF) | |
2529 | return -4; | |
2530 | } | |
2531 | /* | |
2532 | * Make sure the address is not multicast or locally assigned | |
2533 | * that the OUI is not 00-00-00. | |
2534 | */ | |
2535 | if ((sc->tulip_rombuf[0] & 3) != 0) | |
2536 | return -4; | |
2537 | if (sc->tulip_rombuf[0] == 0 && sc->tulip_rombuf[1] == 0 | |
2538 | && sc->tulip_rombuf[2] == 0) | |
2539 | return -4; | |
5d2944c2 | 2540 | bcopy(sc->tulip_rombuf, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); |
984263bc MD |
2541 | sc->tulip_features |= TULIP_HAVE_OKROM; |
2542 | goto check_oui; | |
2543 | } else { | |
2544 | /* | |
2545 | * A number of makers of multiport boards (ZNYX and Cogent) | |
2546 | * only put on one address ROM on their 21040 boards. So | |
2547 | * if the ROM is all zeros (or all 0xFFs), look at the | |
2548 | * previous configured boards (as long as they are on the same | |
2549 | * PCI bus and the bus number is non-zero) until we find the | |
2550 | * master board with address ROM. We then use its address ROM | |
2551 | * as the base for this board. (we add our relative board | |
2552 | * to the last byte of its address). | |
2553 | */ | |
2554 | for (idx = 0; idx < sizeof(sc->tulip_rombuf); idx++) { | |
2555 | if (sc->tulip_rombuf[idx] != 0 && sc->tulip_rombuf[idx] != 0xFF) | |
2556 | break; | |
2557 | } | |
2558 | if (idx == sizeof(sc->tulip_rombuf)) { | |
2559 | int root_unit; | |
2560 | tulip_softc_t *root_sc = NULL; | |
5d2944c2 | 2561 | for (root_unit = sc->tulip_unit - 1; root_unit >= 0; root_unit--) { |
984263bc MD |
2562 | root_sc = tulips[root_unit]; |
2563 | if (root_sc == NULL || (root_sc->tulip_features & (TULIP_HAVE_OKROM|TULIP_HAVE_SLAVEDROM)) == TULIP_HAVE_OKROM) | |
2564 | break; | |
2565 | root_sc = NULL; | |
2566 | } | |
2567 | if (root_sc != NULL && (root_sc->tulip_features & TULIP_HAVE_BASEROM) | |
2568 | && root_sc->tulip_chipid == sc->tulip_chipid | |
2569 | && root_sc->tulip_pci_busno == sc->tulip_pci_busno) { | |
2570 | sc->tulip_features |= TULIP_HAVE_SLAVEDROM; | |
2571 | sc->tulip_boardsw = root_sc->tulip_boardsw; | |
2572 | strcpy(sc->tulip_boardid, root_sc->tulip_boardid); | |
2573 | if (sc->tulip_boardsw->bd_type == TULIP_21140_ISV) { | |
2574 | bcopy(root_sc->tulip_rombuf, sc->tulip_rombuf, | |
2575 | sizeof(sc->tulip_rombuf)); | |
2576 | if (!tulip_srom_decode(sc)) | |
2577 | return -5; | |
2578 | } else { | |
5d2944c2 IV |
2579 | bcopy(root_sc->arpcom.ac_enaddr, sc->arpcom.ac_enaddr, |
2580 | ETHER_ADDR_LEN); | |
2581 | sc->arpcom.ac_enaddr[5] += sc->tulip_unit - root_sc->tulip_unit; | |
984263bc MD |
2582 | } |
2583 | /* | |
2584 | * Now for a truly disgusting kludge: all 4 21040s on | |
2585 | * the ZX314 share the same INTA line so the mapping | |
2586 | * setup by the BIOS on the PCI bridge is worthless. | |
2587 | * Rather than reprogramming the value in the config | |
2588 | * register, we will handle this internally. | |
2589 | */ | |
2590 | if (root_sc->tulip_features & TULIP_HAVE_SHAREDINTR) { | |
2591 | sc->tulip_slaves = root_sc->tulip_slaves; | |
2592 | root_sc->tulip_slaves = sc; | |
2593 | sc->tulip_features |= TULIP_HAVE_SLAVEDINTR; | |
2594 | } | |
2595 | return 0; | |
2596 | } | |
2597 | } | |
2598 | } | |
2599 | ||
2600 | /* | |
2601 | * This is the standard DEC address ROM test. | |
2602 | */ | |
2603 | ||
2604 | if (bcmp(&sc->tulip_rombuf[24], testpat, 8) != 0) | |
2605 | return -3; | |
2606 | ||
2607 | tmpbuf[0] = sc->tulip_rombuf[15]; tmpbuf[1] = sc->tulip_rombuf[14]; | |
2608 | tmpbuf[2] = sc->tulip_rombuf[13]; tmpbuf[3] = sc->tulip_rombuf[12]; | |
2609 | tmpbuf[4] = sc->tulip_rombuf[11]; tmpbuf[5] = sc->tulip_rombuf[10]; | |
2610 | tmpbuf[6] = sc->tulip_rombuf[9]; tmpbuf[7] = sc->tulip_rombuf[8]; | |
2611 | if (bcmp(&sc->tulip_rombuf[0], tmpbuf, 8) != 0) | |
2612 | return -2; | |
2613 | ||
5d2944c2 | 2614 | bcopy(sc->tulip_rombuf, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); |
984263bc | 2615 | |
5d2944c2 | 2616 | cksum = *(u_int16_t *) &sc->arpcom.ac_enaddr[0]; |
984263bc MD |
2617 | cksum *= 2; |
2618 | if (cksum > 65535) cksum -= 65535; | |
5d2944c2 | 2619 | cksum += *(u_int16_t *) &sc->arpcom.ac_enaddr[2]; |
984263bc MD |
2620 | if (cksum > 65535) cksum -= 65535; |
2621 | cksum *= 2; | |
2622 | if (cksum > 65535) cksum -= 65535; | |
5d2944c2 | 2623 | cksum += *(u_int16_t *) &sc->arpcom.ac_enaddr[4]; |
984263bc MD |
2624 | if (cksum >= 65535) cksum -= 65535; |
2625 | ||
2626 | rom_cksum = *(u_int16_t *) &sc->tulip_rombuf[6]; | |
2627 | ||
2628 | if (cksum != rom_cksum) | |
2629 | return -1; | |
2630 | ||
2631 | check_oui: | |
2632 | /* | |
2633 | * Check for various boards based on OUI. Did I say braindead? | |
2634 | */ | |
2635 | for (idx = 0; tulip_vendors[idx].vendor_identify_nic != NULL; idx++) { | |
5d2944c2 | 2636 | if (bcmp(sc->arpcom.ac_enaddr, tulip_vendors[idx].vendor_oui, 3) == 0) { |
984263bc MD |
2637 | (*tulip_vendors[idx].vendor_identify_nic)(sc); |
2638 | break; | |
2639 | } | |
2640 | } | |
2641 | ||
2642 | sc->tulip_features |= TULIP_HAVE_OKROM; | |
2643 | return 0; | |
2644 | } | |
79fe23de | 2645 | |
984263bc | 2646 | static void |
79fe23de | 2647 | tulip_ifmedia_add(tulip_softc_t * const sc) |
984263bc MD |
2648 | { |
2649 | tulip_media_t media; | |
2650 | int medias = 0; | |
2651 | ||
2652 | for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { | |
2653 | if (sc->tulip_mediums[media] != NULL) { | |
2654 | ifmedia_add(&sc->tulip_ifmedia, tulip_media_to_ifmedia[media], | |
2655 | 0, 0); | |
2656 | medias++; | |
2657 | } | |
2658 | } | |
2659 | if (medias == 0) { | |
2660 | sc->tulip_features |= TULIP_HAVE_NOMEDIA; | |
2661 | ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE, 0, 0); | |
2662 | ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_NONE); | |
2663 | } else if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) { | |
2664 | ifmedia_add(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO, 0, 0); | |
2665 | ifmedia_set(&sc->tulip_ifmedia, IFM_ETHER | IFM_AUTO); | |
2666 | } else { | |
2667 | ifmedia_set(&sc->tulip_ifmedia, tulip_media_to_ifmedia[sc->tulip_media]); | |
2668 | sc->tulip_flags |= TULIP_PRINTMEDIA; | |
2669 | tulip_linkup(sc, sc->tulip_media); | |
2670 | } | |
2671 | } | |
2672 | ||
2673 | static int | |
79fe23de | 2674 | tulip_ifmedia_change(struct ifnet *ifp) |
984263bc | 2675 | { |
79fe23de | 2676 | tulip_softc_t *sc = (tulip_softc_t *)ifp->if_softc; |
984263bc MD |
2677 | |
2678 | sc->tulip_flags |= TULIP_NEEDRESET; | |
2679 | sc->tulip_probe_state = TULIP_PROBE_INACTIVE; | |
2680 | sc->tulip_media = TULIP_MEDIA_UNKNOWN; | |
2681 | if (IFM_SUBTYPE(sc->tulip_ifmedia.ifm_media) != IFM_AUTO) { | |
2682 | tulip_media_t media; | |
2683 | for (media = TULIP_MEDIA_UNKNOWN; media < TULIP_MEDIA_MAX; media++) { | |
2684 | if (sc->tulip_mediums[media] != NULL | |
2685 | && sc->tulip_ifmedia.ifm_media == tulip_media_to_ifmedia[media]) { | |
2686 | sc->tulip_flags |= TULIP_PRINTMEDIA; | |
2687 | sc->tulip_flags &= ~TULIP_DIDNWAY; | |
2688 | tulip_linkup(sc, media); | |
2689 | return 0; | |
2690 | } | |
2691 | } | |
2692 | } | |
2693 | sc->tulip_flags &= ~(TULIP_TXPROBE_ACTIVE|TULIP_WANTRXACT); | |
2694 | tulip_reset(sc); | |
2695 | tulip_init(sc); | |
2696 | return 0; | |
2697 | } | |
79fe23de | 2698 | |
984263bc MD |
2699 | /* |
2700 | * Media status callback | |
2701 | */ | |
2702 | static void | |
79fe23de | 2703 | tulip_ifmedia_status(struct ifnet *ifp, struct ifmediareq *req) |
984263bc MD |
2704 | { |
2705 | tulip_softc_t *sc = (tulip_softc_t *)ifp->if_softc; | |
2706 | ||
2707 | if (sc->tulip_media == TULIP_MEDIA_UNKNOWN) | |
2708 | return; | |
2709 | ||
2710 | req->ifm_status = IFM_AVALID; | |
2711 | if (sc->tulip_flags & TULIP_LINKUP) | |
2712 | req->ifm_status |= IFM_ACTIVE; | |
2713 | ||
2714 | req->ifm_active = tulip_media_to_ifmedia[sc->tulip_media]; | |
2715 | } | |
79fe23de | 2716 | |
984263bc | 2717 | static void |
79fe23de | 2718 | tulip_addr_filter(tulip_softc_t *sc) |
984263bc MD |
2719 | { |
2720 | struct ifmultiaddr *ifma; | |
5d2944c2 | 2721 | struct ifnet *ifp; |
984263bc MD |
2722 | u_char *addrp; |
2723 | int multicnt; | |
2724 | ||
2725 | sc->tulip_flags &= ~(TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY|TULIP_ALLMULTI); | |
2726 | sc->tulip_flags |= TULIP_WANTSETUP|TULIP_WANTTXSTART; | |
2727 | sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN; | |
2728 | sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; | |
2729 | #if defined(IFF_ALLMULTI) | |
5d2944c2 | 2730 | if (sc->arpcom.ac_if.if_flags & IFF_ALLMULTI) |
984263bc MD |
2731 | sc->tulip_flags |= TULIP_ALLMULTI ; |
2732 | #endif | |
2733 | ||
2734 | multicnt = 0; | |
5d2944c2 IV |
2735 | ifp = &sc->arpcom.ac_if; |
2736 | TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { | |
984263bc MD |
2737 | if (ifma->ifma_addr->sa_family == AF_LINK) |
2738 | multicnt++; | |
2739 | } | |
2740 | ||
984263bc | 2741 | if (multicnt > 14) { |
79fe23de JS |
2742 | uint32_t *sp = sc->tulip_setupdata; |
2743 | u_int hash; | |
984263bc MD |
2744 | /* |
2745 | * Some early passes of the 21140 have broken implementations of | |
2746 | * hash-perfect mode. When we get too many multicasts for perfect | |
2747 | * filtering with these chips, we need to switch into hash-only | |
2748 | * mode (this is better than all-multicast on network with lots | |
2749 | * of multicast traffic). | |
2750 | */ | |
2751 | if (sc->tulip_features & TULIP_HAVE_BROKEN_HASH) | |
2752 | sc->tulip_flags |= TULIP_WANTHASHONLY; | |
2753 | else | |
2754 | sc->tulip_flags |= TULIP_WANTHASHPERFECT; | |
2755 | /* | |
2756 | * If we have more than 14 multicasts, we have | |
2757 | * go into hash perfect mode (512 bit multicast | |
2758 | * hash and one perfect hardware). | |
2759 | */ | |
2760 | bzero(sc->tulip_setupdata, sizeof(sc->tulip_setupdata)); | |
2761 | ||
5d2944c2 | 2762 | TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { |
984263bc MD |
2763 | if (ifma->ifma_addr->sa_family != AF_LINK) |
2764 | continue; | |
2765 | ||
2766 | hash = tulip_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); | |
5d2944c2 | 2767 | sp[hash >> 4] |= htole32(1 << (hash & 0xF)); |
984263bc MD |
2768 | } |
2769 | /* | |
2770 | * No reason to use a hash if we are going to be | |
2771 | * receiving every multicast. | |
2772 | */ | |
2773 | if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) { | |
5d2944c2 IV |
2774 | hash = tulip_mchash(ifp->if_broadcastaddr); |
2775 | sp[hash >> 4] |= htole32(1 << (hash & 0xF)); | |
984263bc | 2776 | if (sc->tulip_flags & TULIP_WANTHASHONLY) { |
5d2944c2 IV |
2777 | hash = tulip_mchash(sc->arpcom.ac_enaddr); |
2778 | sp[hash >> 4] |= htole32(1 << (hash & 0xF)); | |
984263bc | 2779 | } else { |
5d2944c2 IV |
2780 | sp[39] = TULIP_SP_MAC(((u_int16_t *)sc->arpcom.ac_enaddr)[0]); |
2781 | sp[40] = TULIP_SP_MAC(((u_int16_t *)sc->arpcom.ac_enaddr)[1]); | |
2782 | sp[41] = TULIP_SP_MAC(((u_int16_t *)sc->arpcom.ac_enaddr)[2]); | |
984263bc MD |
2783 | } |
2784 | } | |
2785 | } | |
2786 | if ((sc->tulip_flags & (TULIP_WANTHASHPERFECT|TULIP_WANTHASHONLY)) == 0) { | |
79fe23de | 2787 | uint32_t *sp = sc->tulip_setupdata; |
984263bc MD |
2788 | int idx = 0; |
2789 | if ((sc->tulip_flags & TULIP_ALLMULTI) == 0) { | |
2790 | /* | |
2791 | * Else can get perfect filtering for 16 addresses. | |
2792 | */ | |
5d2944c2 | 2793 | TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { |
984263bc MD |
2794 | if (ifma->ifma_addr->sa_family != AF_LINK) |
2795 | continue; | |
2796 | addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); | |
5d2944c2 IV |
2797 | *sp++ = TULIP_SP_MAC(((u_int16_t *)addrp)[0]); |
2798 | *sp++ = TULIP_SP_MAC(((u_int16_t *)addrp)[1]); | |
2799 | *sp++ = TULIP_SP_MAC(((u_int16_t *)addrp)[2]); | |
984263bc MD |
2800 | idx++; |
2801 | } | |
2802 | /* | |
2803 | * Add the broadcast address. | |
2804 | */ | |
2805 | idx++; | |
5d2944c2 IV |
2806 | *sp++ = TULIP_SP_MAC(0xFFFF); |
2807 | *sp++ = TULIP_SP_MAC(0xFFFF); | |
2808 | *sp++ = TULIP_SP_MAC(0xFFFF); | |
984263bc MD |
2809 | } |
2810 | /* | |
2811 | * Pad the rest with our hardware address | |
2812 | */ | |
2813 | for (; idx < 16; idx++) { | |
5d2944c2 IV |
2814 | *sp++ = TULIP_SP_MAC(((u_int16_t *)sc->arpcom.ac_enaddr)[0]); |
2815 | *sp++ = TULIP_SP_MAC(((u_int16_t *)sc->arpcom.ac_enaddr)[1]); | |
2816 | *sp++ = TULIP_SP_MAC(((u_int16_t *)sc->arpcom.ac_enaddr)[2]); | |
984263bc MD |
2817 | } |
2818 | } | |
2819 | #if defined(IFF_ALLMULTI) | |
2820 | if (sc->tulip_flags & TULIP_ALLMULTI) | |
5d2944c2 | 2821 | sc->arpcom.ac_if.if_flags |= IFF_ALLMULTI; |
984263bc MD |
2822 | #endif |
2823 | } | |
5d2944c2 | 2824 | |
984263bc | 2825 | static void |
79fe23de | 2826 | tulip_reset(tulip_softc_t *sc) |
984263bc MD |
2827 | { |
2828 | tulip_ringinfo_t *ri; | |
5d2944c2 IV |
2829 | tulip_descinfo_t *di; |
2830 | struct mbuf *m; | |
79fe23de | 2831 | uint32_t inreset = (sc->tulip_flags & TULIP_INRESET); |
984263bc MD |
2832 | |
2833 | /* | |
2834 | * Brilliant. Simply brilliant. When switching modes/speeds | |
2835 | * on a 2114*, you need to set the appriopriate MII/PCS/SCL/PS | |
2836 | * bits in CSR6 and then do a software reset to get the 21140 | |
2837 | * to properly reset its internal pathways to the right places. | |
2838 | * Grrrr. | |
2839 | */ | |
2840 | if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0 | |
2841 | && sc->tulip_boardsw->bd_media_preset != NULL) | |
2842 | (*sc->tulip_boardsw->bd_media_preset)(sc); | |
2843 | ||
2844 | TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); | |
2845 | DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at | |
2846 | 33MHz that comes to two microseconds but wait a | |
2847 | bit longer anyways) */ | |
2848 | ||
2849 | if (!inreset) { | |
2850 | sc->tulip_flags |= TULIP_INRESET; | |
2851 | sc->tulip_flags &= ~(TULIP_NEEDRESET|TULIP_RXBUFSLOW); | |
5d2944c2 | 2852 | ifq_clr_oactive(&sc->arpcom.ac_if.if_snd); |
984263bc MD |
2853 | } |
2854 | ||
5d2944c2 IV |
2855 | TULIP_CSR_WRITE(sc, csr_txlist, sc->tulip_txinfo.ri_dma_addr & 0xffffffff); |
2856 | TULIP_CSR_WRITE(sc, csr_rxlist, sc->tulip_rxinfo.ri_dma_addr & 0xffffffff); | |
984263bc MD |
2857 | TULIP_CSR_WRITE(sc, csr_busmode, |
2858 | (1 << (3 /*pci_max_burst_len*/ + 8)) | |
2859 | |TULIP_BUSMODE_CACHE_ALIGN8 | |
2860 | |TULIP_BUSMODE_READMULTIPLE | |
2861 | |(BYTE_ORDER != LITTLE_ENDIAN ? | |
2862 | TULIP_BUSMODE_DESC_BIGENDIAN : 0)); | |
2863 | ||
2864 | sc->tulip_txtimer = 0; | |
2865 | sc->tulip_txq.ifq_maxlen = TULIP_TXDESCS; | |
2866 | /* | |
2867 | * Free all the mbufs that were on the transmit ring. | |
2868 | */ | |
984263bc | 2869 | ri = &sc->tulip_txinfo; |
5d2944c2 IV |
2870 | for (di = ri->ri_first; di < ri->ri_last; di++) { |
2871 | m = tulip_dequeue_mbuf(ri, di, SYNC_NONE); | |
2872 | if (m != NULL) | |
2873 | m_freem(m); | |
2874 | di->di_desc->d_status = 0; | |
2875 | } | |
2876 | ||
984263bc MD |
2877 | ri->ri_nextin = ri->ri_nextout = ri->ri_first; |
2878 | ri->ri_free = ri->ri_max; | |
5d2944c2 | 2879 | TULIP_TXDESC_PRESYNC(ri); |
984263bc MD |
2880 | |
2881 | /* | |
5d2944c2 | 2882 | * We need to collect all the mbufs that were on the |
984263bc MD |
2883 | * receive ring before we reinit it either to put |
2884 | * them back on or to know if we have to allocate | |
2885 | * more. | |
2886 | */ | |
2887 | ri = &sc->tulip_rxinfo; | |
2888 | ri->ri_nextin = ri->ri_nextout = ri->ri_first; | |
2889 | ri->ri_free = ri->ri_max; | |
2890 | for (di = ri->ri_first; di < ri->ri_last; di++) { | |
5d2944c2 IV |
2891 | di->di_desc->d_status = 0; |
2892 | di->di_desc->d_length1 = 0; di->di_desc->d_addr1 = 0; | |
2893 | di->di_desc->d_length2 = 0; di->di_desc->d_addr2 = 0; | |
2894 | } | |
2895 | TULIP_RXDESC_PRESYNC(ri); | |
2896 | for (di = ri->ri_first; di < ri->ri_last; di++) { | |
2897 | m = tulip_dequeue_mbuf(ri, di, SYNC_NONE); | |
2898 | if (m != NULL) | |
2899 | m_freem(m); | |
984263bc | 2900 | } |
984263bc MD |
2901 | |
2902 | /* | |
5d2944c2 | 2903 | * If tulip_reset is being called recursively, exit quickly knowing |
984263bc MD |
2904 | * that when the outer tulip_reset returns all the right stuff will |
2905 | * have happened. | |
2906 | */ | |
2907 | if (inreset) | |
2908 | return; | |
2909 | ||
2910 | sc->tulip_intrmask |= TULIP_STS_NORMALINTR|TULIP_STS_RXINTR|TULIP_STS_TXINTR | |
2911 | |TULIP_STS_ABNRMLINTR|TULIP_STS_SYSERROR|TULIP_STS_TXSTOPPED | |
2912 | |TULIP_STS_TXUNDERFLOW|TULIP_STS_TXBABBLE | |
2913 | |TULIP_STS_RXSTOPPED; | |
2914 | ||
2915 | if ((sc->tulip_flags & TULIP_DEVICEPROBE) == 0) | |
2916 | (*sc->tulip_boardsw->bd_media_select)(sc); | |
984263bc MD |
2917 | tulip_media_print(sc); |
2918 | if (sc->tulip_features & TULIP_HAVE_DUALSENSE) | |
2919 | TULIP_CSR_WRITE(sc, csr_sia_status, TULIP_CSR_READ(sc, csr_sia_status)); | |
2920 | ||
2921 | sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_WANTSETUP|TULIP_INRESET | |
2922 | |TULIP_RXACT); | |
2923 | tulip_addr_filter(sc); | |
2924 | } | |
79fe23de | 2925 | |
984263bc | 2926 | static void |
79fe23de | 2927 | tulip_init(tulip_softc_t * const sc) |
984263bc | 2928 | { |
5d2944c2 IV |
2929 | if (sc->arpcom.ac_if.if_flags & IFF_UP) { |
2930 | if ((sc->arpcom.ac_if.if_flags & IFF_RUNNING) == 0) { | |
984263bc MD |
2931 | /* initialize the media */ |
2932 | tulip_reset(sc); | |
2933 | } | |
5d2944c2 IV |
2934 | sc->arpcom.ac_if.if_flags |= IFF_RUNNING; |
2935 | if (sc->arpcom.ac_if.if_flags & IFF_PROMISC) { | |
984263bc MD |
2936 | sc->tulip_flags |= TULIP_PROMISC; |
2937 | sc->tulip_cmdmode |= TULIP_CMD_PROMISCUOUS; | |
2938 | sc->tulip_intrmask |= TULIP_STS_TXINTR; | |
2939 | } else { | |
2940 | sc->tulip_flags &= ~TULIP_PROMISC; | |
2941 | sc->tulip_cmdmode &= ~TULIP_CMD_PROMISCUOUS; | |
2942 | if (sc->tulip_flags & TULIP_ALLMULTI) { | |
2943 | sc->tulip_cmdmode |= TULIP_CMD_ALLMULTI; | |
2944 | } else { | |
2945 | sc->tulip_cmdmode &= ~TULIP_CMD_ALLMULTI; | |
2946 | } | |
2947 | } | |
2948 | sc->tulip_cmdmode |= TULIP_CMD_TXRUN; | |
2949 | if ((sc->tulip_flags & (TULIP_TXPROBE_ACTIVE|TULIP_WANTSETUP)) == 0) { | |
2950 | tulip_rx_intr(sc); | |
2951 | sc->tulip_cmdmode |= TULIP_CMD_RXRUN; | |
2952 | sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; | |
2953 | } else { | |
5d2944c2 | 2954 | ifq_set_oactive(&sc->arpcom.ac_if.if_snd); |
984263bc MD |
2955 | sc->tulip_cmdmode &= ~TULIP_CMD_RXRUN; |
2956 | sc->tulip_intrmask &= ~TULIP_STS_RXSTOPPED; | |
2957 | } | |
2958 | TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); | |
2959 | TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); | |
2960 | if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP) | |
2961 | tulip_txput_setup(sc); | |
2962 | } else { | |
5d2944c2 | 2963 | sc->arpcom.ac_if.if_flags &= ~IFF_RUNNING; |
984263bc MD |
2964 | tulip_reset(sc); |
2965 | } | |
2966 | } | |
79fe23de | 2967 | |
5d2944c2 IV |
2968 | #define DESC_STATUS(di) (((volatile tulip_desc_t *)((di)->di_desc))->d_status) |
2969 | #define DESC_FLAG(di) ((di)->di_desc->d_flag) | |
2970 | ||
984263bc | 2971 | static void |
79fe23de | 2972 | tulip_rx_intr(tulip_softc_t *sc) |
984263bc | 2973 | { |
79fe23de | 2974 | tulip_ringinfo_t *ri = &sc->tulip_rxinfo; |
5d2944c2 | 2975 | struct ifnet *ifp = &sc->arpcom.ac_if; |
984263bc | 2976 | int fillok = 1; |
984263bc MD |
2977 | |
2978 | for (;;) { | |
5d2944c2 | 2979 | tulip_descinfo_t *eop = ri->ri_nextin, *dip; |
984263bc MD |
2980 | int total_len = 0, last_offset = 0; |
2981 | struct mbuf *ms = NULL, *me = NULL; | |
2982 | int accept = 0; | |
5d2944c2 | 2983 | int error; |
984263bc | 2984 | |
5d2944c2 | 2985 | if (fillok && (ri->ri_max - ri->ri_free) < TULIP_RXQ_TARGET) |
984263bc MD |
2986 | goto queue_mbuf; |
2987 | ||
984263bc MD |
2988 | /* |
2989 | * If the TULIP has no descriptors, there can't be any receive | |
2990 | * descriptors to process. | |
2991 | */ | |
2992 | if (eop == ri->ri_nextout) | |
2993 | break; | |
2994 | ||
2995 | /* | |
2996 | * 90% of the packets will fit in one descriptor. So we optimize | |
2997 | * for that case. | |
2998 | */ | |
5d2944c2 IV |
2999 | TULIP_RXDESC_POSTSYNC(ri); |
3000 | if ((DESC_STATUS(eop) & (TULIP_DSTS_OWNER|TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) == (TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) { | |
3001 | ms = tulip_dequeue_mbuf(ri, eop, SYNC_RX); | |
984263bc | 3002 | me = ms; |
5d2944c2 | 3003 | ri->ri_free++; |
984263bc MD |
3004 | } else { |
3005 | /* | |
3006 | * If still owned by the TULIP, don't touch it. | |
3007 | */ | |
5d2944c2 | 3008 | if (DESC_STATUS(eop) & TULIP_DSTS_OWNER) |
984263bc MD |
3009 | break; |
3010 | ||
3011 | /* | |
5d2944c2 IV |
3012 | * It is possible (though improbable unless MCLBYTES < 1518) for |
3013 | * a received packet to cross more than one receive descriptor. | |
3014 | * We first loop through the descriptor ring making sure we have | |
3015 | * received a complete packet. If not, we bail until the next | |
3016 | * interrupt. | |
984263bc | 3017 | */ |
5d2944c2 IV |
3018 | dip = eop; |
3019 | while ((DESC_STATUS(eop) & TULIP_DSTS_RxLASTDESC) == 0) { | |
984263bc MD |
3020 | if (++eop == ri->ri_last) |
3021 | eop = ri->ri_first; | |
5d2944c2 IV |
3022 | TULIP_RXDESC_POSTSYNC(ri); |
3023 | if (eop == ri->ri_nextout || (DESC_STATUS(eop) & TULIP_DSTS_OWNER)) { | |
984263bc MD |
3024 | return; |
3025 | } | |
3026 | total_len++; | |
3027 | } | |
3028 | ||
3029 | /* | |
3030 | * Dequeue the first buffer for the start of the packet. Hopefully | |
3031 | * this will be the only one we need to dequeue. However, if the | |
3032 | * packet consumed multiple descriptors, then we need to dequeue | |
3033 | * those buffers and chain to the starting mbuf. All buffers but | |
3034 | * the last buffer have the same length so we can set that now. | |
3035 | * (we add to last_offset instead of multiplying since we normally | |
5d2944c2 | 3036 | * won't go into the loop and thereby saving ourselves from |
984263bc MD |
3037 | * doing a multiplication by 0 in the normal case). |
3038 | */ | |
5d2944c2 IV |
3039 | ms = tulip_dequeue_mbuf(ri, dip, SYNC_RX); |
3040 | ri->ri_free++; | |
984263bc | 3041 | for (me = ms; total_len > 0; total_len--) { |
984263bc MD |
3042 | me->m_len = TULIP_RX_BUFLEN; |
3043 | last_offset += TULIP_RX_BUFLEN; | |
5d2944c2 IV |
3044 | if (++dip == ri->ri_last) |
3045 | dip = ri->ri_first; | |
3046 | me->m_next = tulip_dequeue_mbuf(ri, dip, SYNC_RX); | |
3047 | ri->ri_free++; | |
984263bc MD |
3048 | me = me->m_next; |
3049 | } | |
5d2944c2 | 3050 | KASSERT(dip == eop, ("mismatched descinfo structs")); |
984263bc MD |
3051 | } |
3052 | ||
3053 | /* | |
3054 | * Now get the size of received packet (minus the CRC). | |
3055 | */ | |
5d2944c2 | 3056 | total_len = ((DESC_STATUS(eop) >> 16) & 0x7FFF) - ETHER_CRC_LEN; |
984263bc | 3057 | if ((sc->tulip_flags & TULIP_RXIGNORE) == 0 |
5d2944c2 | 3058 | && ((DESC_STATUS(eop) & TULIP_DSTS_ERRSUM) == 0)) { |
984263bc | 3059 | me->m_len = total_len - last_offset; |
984263bc MD |
3060 | sc->tulip_flags |= TULIP_RXACT; |
3061 | accept = 1; | |
3062 | } else { | |
d40991ef | 3063 | IFNET_STAT_INC(ifp, ierrors, 1); |
5d2944c2 | 3064 | if (DESC_STATUS(eop) & (TULIP_DSTS_RxBADLENGTH|TULIP_DSTS_RxOVERFLOW|TULIP_DSTS_RxWATCHDOG)) { |
984263bc MD |
3065 | sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++; |
3066 | } else { | |
5d2944c2 | 3067 | if (DESC_STATUS(eop) & TULIP_DSTS_RxTOOLONG) { |
984263bc | 3068 | sc->tulip_dot3stats.dot3StatsFrameTooLongs++; |
984263bc | 3069 | } |
5d2944c2 IV |
3070 | if (DESC_STATUS(eop) & TULIP_DSTS_RxBADCRC) { |
3071 | if (DESC_STATUS(eop) & TULIP_DSTS_RxDRBBLBIT) { | |
984263bc | 3072 | sc->tulip_dot3stats.dot3StatsAlignmentErrors++; |
984263bc MD |
3073 | } else { |
3074 | sc->tulip_dot3stats.dot3StatsFCSErrors++; | |
984263bc MD |
3075 | } |
3076 | } | |
984263bc | 3077 | } |
984263bc | 3078 | } |
d40991ef | 3079 | IFNET_STAT_INC(ifp, ipackets, 1); |
984263bc MD |
3080 | if (++eop == ri->ri_last) |
3081 | eop = ri->ri_first; | |
3082 | ri->ri_nextin = eop; | |
3083 | queue_mbuf: | |
3084 | /* | |
5d2944c2 IV |
3085 | * We have received a good packet that needs to be passed up the |
3086 | * stack. | |
984263bc | 3087 | */ |
5d2944c2 | 3088 | if (accept) { |
984263bc | 3089 | struct mbuf *m0; |
50503f0f | 3090 | |
5d2944c2 IV |
3091 | KASSERT(ms != NULL, ("no packet to accept")); |
3092 | /* | |
3093 | * Update the header for the mbuf referencing this receive | |
3094 | * buffer and pass it up the stack. Allocate a new mbuf cluster | |
3095 | * to replace the one we just passed up the stack. | |
3096 | * | |
3097 | * Note that if this packet crossed multiple descriptors | |
3098 | * we don't even try to reallocate all the mbufs here. | |
3099 | * Instead we rely on the test at the beginning of | |
3100 | * the loop to refill for the extra consumed mbufs. | |
3101 | */ | |
3102 | ms->m_pkthdr.len = total_len; | |
3103 | ms->m_pkthdr.rcvif = ifp; | |
3104 | m0 = ms; | |
3105 | ifp->if_input(ifp, m0, NULL, -1); | |
3106 | ms = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); | |
3107 | } else if (ms == NULL) { | |
3108 | /* | |
3109 | * If we are priming the TULIP with mbufs, then allocate | |
3110 | * a new cluster for the next descriptor. | |
3111 | */ | |
3112 | ms = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); | |
984263bc MD |
3113 | } |
3114 | if (ms == NULL) { | |
3115 | /* | |
3116 | * Couldn't allocate a new buffer. Don't bother | |
3117 | * trying to replenish the receive queue. | |
3118 | */ | |
3119 | fillok = 0; | |
3120 | sc->tulip_flags |= TULIP_RXBUFSLOW; | |
984263bc MD |
3121 | continue; |
3122 | } | |
3123 | /* | |
3124 | * Now give the buffer(s) to the TULIP and save in our | |
3125 | * receive queue. | |
3126 | */ | |
3127 | do { | |
5d2944c2 IV |
3128 | tulip_descinfo_t * const nextout = ri->ri_nextout; |
3129 | ||
3130 | M_ASSERTPKTHDR(ms); | |
3131 | KASSERT(ms->m_data == ms->m_ext.ext_buf, | |
3132 | ("rx mbuf data doesn't point to cluster")); | |
3133 | ms->m_len = ms->m_pkthdr.len = TULIP_RX_BUFLEN; | |
3134 | error = bus_dmamap_load_mbuf(ri->ri_data_tag, *nextout->di_map, ms, | |
3135 | tulip_dma_map_rxbuf, nextout->di_desc, BUS_DMA_NOWAIT); | |
3136 | if (error) { | |
3137 | device_printf(sc->tulip_dev, | |
3138 | "unable to load rx map, error = %d\n", error); | |
3139 | panic("tulip_rx_intr"); /* XXX */ | |
3140 | } | |
3141 | nextout->di_desc->d_status = TULIP_DSTS_OWNER; | |
3142 | KASSERT(nextout->di_mbuf == NULL, ("clobbering earlier rx mbuf")); | |
3143 | nextout->di_mbuf = ms; | |
3144 | TULIP_RXDESC_POSTSYNC(ri); | |
984263bc MD |
3145 | if (++ri->ri_nextout == ri->ri_last) |
3146 | ri->ri_nextout = ri->ri_first; | |
5d2944c2 | 3147 | ri->ri_free--; |
984263bc MD |
3148 | me = ms->m_next; |
3149 | ms->m_next = NULL; | |
984263bc MD |
3150 | } while ((ms = me) != NULL); |
3151 | ||
5d2944c2 | 3152 | if ((ri->ri_max - ri->ri_free) >= TULIP_RXQ_TARGET) |
984263bc | 3153 | sc->tulip_flags &= ~TULIP_RXBUFSLOW; |
984263bc | 3154 | } |
984263bc | 3155 | } |
79fe23de | 3156 | |
984263bc | 3157 | static int |
79fe23de | 3158 | tulip_tx_intr(tulip_softc_t *sc) |
984263bc | 3159 | { |
79fe23de | 3160 | tulip_ringinfo_t *ri = &sc->tulip_txinfo; |
984263bc MD |
3161 | struct mbuf *m; |
3162 | int xmits = 0; | |
3163 | int descs = 0; | |
3164 | ||
3165 | while (ri->ri_free < ri->ri_max) { | |
79fe23de | 3166 | uint32_t d_flag; |
984263bc | 3167 | |
5d2944c2 IV |
3168 | TULIP_TXDESC_POSTSYNC(ri); |
3169 | if (DESC_STATUS(ri->ri_nextin) & TULIP_DSTS_OWNER) | |
984263bc MD |
3170 | break; |
3171 | ||
3172 | ri->ri_free++; | |
3173 | descs++; | |
5d2944c2 | 3174 | d_flag = DESC_FLAG(ri->ri_nextin); |
984263bc MD |
3175 | if (d_flag & TULIP_DFLAG_TxLASTSEG) { |
3176 | if (d_flag & TULIP_DFLAG_TxSETUPPKT) { | |
3177 | /* | |
3178 | * We've just finished processing a setup packet. | |
3179 | * Mark that we finished it. If there's not | |
3180 | * another pending, startup the TULIP receiver. | |
3181 | * Make sure we ack the RXSTOPPED so we won't get | |
3182 | * an abormal interrupt indication. | |
3183 | */ | |
5d2944c2 IV |
3184 | bus_dmamap_sync(sc->tulip_setup_tag, sc->tulip_setup_map, |
3185 | BUS_DMASYNC_POSTWRITE); | |
984263bc | 3186 | sc->tulip_flags &= ~(TULIP_DOINGSETUP|TULIP_HASHONLY); |
5d2944c2 | 3187 | if (DESC_FLAG(ri->ri_nextin) & TULIP_DFLAG_TxINVRSFILT) |
984263bc MD |
3188 | sc->tulip_flags |= TULIP_HASHONLY; |
3189 | if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == 0) { | |
3190 | tulip_rx_intr(sc); | |
3191 | sc->tulip_cmdmode |= TULIP_CMD_RXRUN; | |
3192 | sc->tulip_intrmask |= TULIP_STS_RXSTOPPED; | |
3193 | TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED); | |
3194 | TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); | |
3195 | TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); | |
3196 | } | |
3197 | } else { | |
5d2944c2 IV |
3198 | const uint32_t d_status = DESC_STATUS(ri->ri_nextin); |
3199 | m = tulip_dequeue_mbuf(ri, ri->ri_nextin, SYNC_TX); | |
984263bc | 3200 | if (m != NULL) { |
984263bc | 3201 | m_freem(m); |
984263bc MD |
3202 | } |
3203 | if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) { | |
3204 | tulip_mediapoll_event_t event = TULIP_MEDIAPOLL_TXPROBE_OK; | |
3205 | if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxEXCCOLL)) { | |
984263bc MD |
3206 | event = TULIP_MEDIAPOLL_TXPROBE_FAILED; |
3207 | } | |
3208 | (*sc->tulip_boardsw->bd_media_poll)(sc, event); | |
3209 | /* | |
3210 | * Escape from the loop before media poll has reset the TULIP! | |
3211 | */ | |
3212 | break; | |
3213 | } else { | |
3214 | xmits++; | |
3215 | if (d_status & TULIP_DSTS_ERRSUM) { | |
5d2944c2 | 3216 | IFNET_STAT_INC(&sc->arpcom.ac_if, oerrors, 1); |
984263bc MD |
3217 | if (d_status & TULIP_DSTS_TxEXCCOLL) |
3218 | sc->tulip_dot3stats.dot3StatsExcessiveCollisions++; | |
3219 | if (d_status & TULIP_DSTS_TxLATECOLL) | |
3220 | sc->tulip_dot3stats.dot3StatsLateCollisions++; | |
3221 | if (d_status & (TULIP_DSTS_TxNOCARR|TULIP_DSTS_TxCARRLOSS)) | |
3222 | sc->tulip_dot3stats.dot3StatsCarrierSenseErrors++; | |
3223 | if (d_status & (TULIP_DSTS_TxUNDERFLOW|TULIP_DSTS_TxBABBLE)) | |
3224 | sc->tulip_dot3stats.dot3StatsInternalMacTransmitErrors++; | |
3225 | if (d_status & TULIP_DSTS_TxUNDERFLOW) | |
3226 | sc->tulip_dot3stats.dot3StatsInternalTransmitUnderflows++; | |
3227 | if (d_status & TULIP_DSTS_TxBABBLE) | |
3228 | sc->tulip_dot3stats.dot3StatsInternalTransmitBabbles++; | |
3229 | } else { | |
3230 | u_int32_t collisions = | |
3231 | (d_status & TULIP_DSTS_TxCOLLMASK) | |
3232 | >> TULIP_DSTS_V_TxCOLLCNT; | |
5d2944c2 | 3233 | IFNET_STAT_INC(&sc->arpcom.ac_if, collisions, collisions); |
984263bc MD |
3234 | if (collisions == 1) |
3235 | sc->tulip_dot3stats.dot3StatsSingleCollisionFrames++; | |
3236 | else if (collisions > 1) | |
3237 | sc->tulip_dot3stats.dot3StatsMultipleCollisionFrames++; | |
3238 | else if (d_status & TULIP_DSTS_TxDEFERRED) | |
3239 | sc->tulip_dot3stats.dot3StatsDeferredTransmissions++; | |
3240 | /* | |
3241 | * SQE is only valid for 10baseT/BNC/AUI when not | |
3242 | * running in full-duplex. In order to speed up the | |
3243 | * test, the corresponding bit in tulip_flags needs to | |
3244 | * set as well to get us to count SQE Test Errors. | |
3245 | */ | |
3246 | if (d_status & TULIP_DSTS_TxNOHRTBT & sc->tulip_flags) | |
3247 | sc->tulip_dot3stats.dot3StatsSQETestErrors++; | |
3248 | } | |
3249 | } | |
3250 | } | |
3251 | } | |
3252 | ||
3253 | if (++ri->ri_nextin == ri->ri_last) | |
3254 | ri->ri_nextin = ri->ri_first; | |
3255 | ||
3256 | if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) | |
5d2944c2 | 3257 | ifq_clr_oactive(&sc->arpcom.ac_if.if_snd); |
984263bc MD |
3258 | } |
3259 | /* | |
3260 | * If nothing left to transmit, disable the timer. | |
3261 | * Else if progress, reset the timer back to 2 ticks. | |
3262 | */ | |
3263 | if (ri->ri_free == ri->ri_max || (sc->tulip_flags & TULIP_TXPROBE_ACTIVE)) | |
3264 | sc->tulip_txtimer = 0; | |
3265 | else if (xmits > 0) | |
5d2944c2 IV |
3266 | sc->tulip_txtimer = TULIP_TXTIMER; |
3267 | IFNET_STAT_INC(&sc->arpcom.ac_if, opackets, xmits); | |
984263bc MD |
3268 | return descs; |
3269 | } | |
79fe23de | 3270 | |
984263bc | 3271 | static void |
79fe23de | 3272 | tulip_print_abnormal_interrupt(tulip_softc_t *sc, uint32_t csr) |
984263bc MD |
3273 | { |
3274 | const char * const *msgp = tulip_status_bits; | |
3275 | const char *sep; | |
79fe23de | 3276 | uint32_t mask; |
984263bc MD |
3277 | const char thrsh[] = "72|128\0\0\0" "96|256\0\0\0" "128|512\0\0" "160|1024"; |
3278 | ||
c157ff7a | 3279 | csr &= (1 << (NELEM(tulip_status_bits))) - 1; |
5d2944c2 | 3280 | if_printf(&sc->arpcom.ac_if, "abnormal interrupt:"); |
984263bc MD |
3281 | for (sep = " ", mask = 1; mask <= csr; mask <<= 1, msgp++) { |
3282 | if ((csr & mask) && *msgp != NULL) { | |
e3869ec7 | 3283 | kprintf("%s%s", sep, *msgp); |
984263bc MD |
3284 | if (mask == TULIP_STS_TXUNDERFLOW && (sc->tulip_flags & TULIP_NEWTXTHRESH)) { |
3285 | sc->tulip_flags &= ~TULIP_NEWTXTHRESH; | |
3286 | if (sc->tulip_cmdmode & TULIP_CMD_STOREFWD) { | |
e3869ec7 | 3287 | kprintf(" (switching to store-and-forward mode)"); |
984263bc | 3288 | } else { |
e3869ec7 | 3289 | kprintf(" (raising TX threshold to %s)", |
984263bc MD |
3290 | &thrsh[9 * ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) >> 14)]); |
3291 | } | |
3292 | } | |
3293 | sep = ", "; | |
3294 | } | |
3295 | } | |
e3869ec7 | 3296 | kprintf("\n"); |
984263bc MD |
3297 | } |
3298 | ||
3299 | static void | |
3a59080c | 3300 | tulip_intr_handler(tulip_softc_t *sc) |
984263bc | 3301 | { |
79fe23de | 3302 | uint32_t csr; |
984263bc MD |
3303 | |
3304 | while ((csr = TULIP_CSR_READ(sc, csr_status)) & sc->tulip_intrmask) { | |
984263bc MD |
3305 | TULIP_CSR_WRITE(sc, csr_status, csr); |
3306 | ||
3307 | if (csr & TULIP_STS_SYSERROR) { | |
3308 | sc->tulip_last_system_error = (csr & TULIP_STS_ERRORMASK) >> TULIP_STS_ERR_SHIFT; | |
3309 | if (sc->tulip_flags & TULIP_NOMESSAGES) { | |
3310 | sc->tulip_flags |= TULIP_SYSTEMERROR; | |
3311 | } else { | |
5d2944c2 | 3312 | if_printf(&sc->arpcom.ac_if, "system error: %s\n", |
984263bc MD |
3313 | tulip_system_errors[sc->tulip_last_system_error]); |
3314 | } | |
3315 | sc->tulip_flags |= TULIP_NEEDRESET; | |
3316 | sc->tulip_system_errors++; | |
3317 | break; | |
3318 | } | |
3319 | if (csr & (TULIP_STS_LINKPASS|TULIP_STS_LINKFAIL) & sc->tulip_intrmask) { | |
984263bc MD |
3320 | if (sc->tulip_boardsw->bd_media_poll != NULL) { |
3321 | (*sc->tulip_boardsw->bd_media_poll)(sc, csr & TULIP_STS_LINKFAIL | |
3322 | ? TULIP_MEDIAPOLL_LINKFAIL | |
3323 | : TULIP_MEDIAPOLL_LINKPASS); | |
3324 | csr &= ~TULIP_STS_ABNRMLINTR; | |
3325 | } | |
3326 | tulip_media_print(sc); | |
3327 | } | |
3328 | if (csr & (TULIP_STS_RXINTR|TULIP_STS_RXNOBUF)) { | |
3329 | u_int32_t misses = TULIP_CSR_READ(sc, csr_missed_frames); | |
3330 | if (csr & TULIP_STS_RXNOBUF) | |
3331 | sc->tulip_dot3stats.dot3StatsMissedFrames += misses & 0xFFFF; | |
3332 | /* | |
3333 | * Pass 2.[012] of the 21140A-A[CDE] may hang and/or corrupt data | |
3334 | * on receive overflows. | |
3335 | */ | |
5d2944c2 | 3336 | if ((misses & 0x0FFE0000) && (sc->tulip_features & TULIP_HAVE_RXBADOVRFLW)) { |
984263bc MD |
3337 | sc->tulip_dot3stats.dot3StatsInternalMacReceiveErrors++; |
3338 | /* | |
3339 | * Stop the receiver process and spin until it's stopped. | |
3340 | * Tell rx_intr to drop the packets it dequeues. | |
3341 | */ | |
3342 | TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode & ~TULIP_CMD_RXRUN); | |
3343 | while ((TULIP_CSR_READ(sc, csr_status) & TULIP_STS_RXSTOPPED) == 0) | |
3344 | ; | |
3345 | TULIP_CSR_WRITE(sc, csr_status, TULIP_STS_RXSTOPPED); | |
3346 | sc->tulip_flags |= TULIP_RXIGNORE; | |
3347 | } | |
3348 | tulip_rx_intr(sc); | |
3349 | if (sc->tulip_flags & TULIP_RXIGNORE) { | |
3350 | /* | |
3351 | * Restart the receiver. | |
3352 | */ | |
3353 | sc->tulip_flags &= ~TULIP_RXIGNORE; | |
3354 | TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); | |
3355 | } | |
3356 | } | |
3357 | if (csr & TULIP_STS_ABNRMLINTR) { | |
3358 | u_int32_t tmp = csr & sc->tulip_intrmask | |
3359 | & ~(TULIP_STS_NORMALINTR|TULIP_STS_ABNRMLINTR); | |
3360 | if (csr & TULIP_STS_TXUNDERFLOW) { | |
3361 | if ((sc->tulip_cmdmode & TULIP_CMD_THRESHOLDCTL) != TULIP_CMD_THRSHLD160) { | |
3362 | sc->tulip_cmdmode += TULIP_CMD_THRSHLD96; | |
3363 | sc->tulip_flags |= TULIP_NEWTXTHRESH; | |
3364 | } else if (sc->tulip_features & TULIP_HAVE_STOREFWD) { | |
3365 | sc->tulip_cmdmode |= TULIP_CMD_STOREFWD; | |
3366 | sc->tulip_flags |= TULIP_NEWTXTHRESH; | |
3367 | } | |
3368 | } | |
3369 | if (sc->tulip_flags & TULIP_NOMESSAGES) { | |
3370 | sc->tulip_statusbits |= tmp; | |
3371 | } else { | |
3372 | tulip_print_abnormal_interrupt(sc, tmp); | |
3373 | sc->tulip_flags |= TULIP_NOMESSAGES; | |
3374 | } | |
3375 | TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode); | |
3376 | } | |
3377 | if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_TXPROBE_ACTIVE|TULIP_DOINGSETUP|TULIP_PROMISC)) { | |
3378 | tulip_tx_intr(sc); | |
3379 | if ((sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) | |
5d2944c2 | 3380 | if_devstart(&sc->arpcom.ac_if); |
984263bc MD |
3381 | } |
3382 | } | |
3383 | if (sc->tulip_flags & TULIP_NEEDRESET) { | |
3384 | tulip_reset(sc); | |
3385 | tulip_init(sc); | |
3386 | } | |
984263bc MD |
3387 | } |
3388 | ||
984263bc | 3389 | static void |
79fe23de | 3390 | tulip_intr_shared(void *arg) |
984263bc | 3391 | { |
3a59080c | 3392 | tulip_softc_t *sc; |
984263bc | 3393 | |
3a59080c JS |
3394 | for (sc = arg; sc != NULL; sc = sc->tulip_slaves) |
3395 | tulip_intr_handler(sc); | |
984263bc MD |
3396 | } |
3397 | ||
3398 | static void | |
79fe23de | 3399 | tulip_intr_normal(void *arg) |
984263bc | 3400 | { |
79fe23de | 3401 | tulip_softc_t *sc = (tulip_softc_t *)arg; |
984263bc | 3402 | |
3a59080c | 3403 | tulip_intr_handler(sc); |
984263bc | 3404 | } |
79fe23de | 3405 | |
984263bc | 3406 | static struct mbuf * |
79fe23de | 3407 | tulip_txput(tulip_softc_t *sc, struct mbuf *m) |
984263bc | 3408 | { |
5d2944c2 IV |
3409 | tulip_ringinfo_t * const ri = &sc->tulip_txinfo; |
3410 | tulip_descinfo_t *eop, *nextout; | |
984263bc | 3411 | int segcnt, free; |
79fe23de | 3412 | uint32_t d_status; |
5d2944c2 IV |
3413 | bus_dma_segment_t segs[TULIP_MAX_TXSEG]; |
3414 | bus_dmamap_t *map; | |
3415 | int error, nsegs; | |
984263bc | 3416 | struct mbuf *m0; |
984263bc | 3417 | |
984263bc MD |
3418 | /* |
3419 | * Now we try to fill in our transmit descriptors. This is | |
3420 | * a bit reminiscent of going on the Ark two by two | |
3421 | * since each descriptor for the TULIP can describe | |
3422 | * two buffers. So we advance through packet filling | |
3423 | * each of the two entries at a time to to fill each | |
3424 | * descriptor. Clear the first and last segment bits | |
3425 | * in each descriptor (actually just clear everything | |
3426 | * but the end-of-ring or chain bits) to make sure | |
3427 | * we don't get messed up by previously sent packets. | |
3428 | * | |
3429 | * We may fail to put the entire packet on the ring if | |
3430 | * there is either not enough ring entries free or if the | |
3431 | * packet has more than MAX_TXSEG segments. In the former | |
3432 | * case we will just wait for the ring to empty. In the | |
3433 | * latter case we have to recopy. | |
3434 | */ | |
984263bc | 3435 | m0 = m; |
984263bc MD |
3436 | d_status = 0; |
3437 | eop = nextout = ri->ri_nextout; | |
3438 | segcnt = 0; | |
3439 | free = ri->ri_free; | |
3440 | ||
5d2944c2 IV |
3441 | /* |
3442 | * Reclaim some tx descriptors if we are out since we need at least one | |
3443 | * free descriptor so that we have a dma_map to load the mbuf. | |
3444 | */ | |
3445 | if (free == 0) { | |
3446 | free += tulip_tx_intr(sc); | |
3447 | } | |
3448 | if (free == 0) { | |
3449 | sc->tulip_flags |= TULIP_WANTTXSTART; | |
3450 | goto finish; | |
3451 | } | |
3452 | error = bus_dmamap_load_mbuf_segment(ri->ri_data_tag, *eop->di_map, m, segs, | |
3453 | 1, &nsegs, BUS_DMA_NOWAIT); | |
3454 | if (error != 0) { | |
3455 | if (error == EFBIG) { | |
3456 | /* | |
3457 | * The packet exceeds the number of transmit buffer | |
3458 | * entries that we can use for one packet, so we have | |
3459 | * to recopy it into one mbuf and then try again. If | |
3460 | * we can't recopy it, try again later. | |
3461 | */ | |
3462 | m0 = m_defrag(m, M_NOWAIT); | |
3463 | if (m0 == NULL) { | |
3464 | sc->tulip_flags |= TULIP_WANTTXSTART; | |
3465 | goto finish; | |
984263bc | 3466 | } |
5d2944c2 IV |
3467 | m = m0; |
3468 | error = bus_dmamap_load_mbuf_segment(ri->ri_data_tag, *eop->di_map, | |
3469 | m, segs, 1, &nsegs, BUS_DMA_NOWAIT); | |
3470 | } | |
3471 | if (error != 0) { | |
3472 | device_printf(sc->tulip_dev, | |
3473 | "unable to load tx map, error = %d\n", error); | |
3474 | goto finish; | |
984263bc | 3475 | } |
5d2944c2 IV |
3476 | } |
3477 | /* | |
3478 | * Each descriptor allows for up to 2 fragments since we don't use | |
3479 | * the descriptor chaining mode in this driver. | |
3480 | */ | |
3481 | if ((free -= (nsegs + 1) / 2) <= 0 | |
3482 | /* | |
3483 | * See if there's any unclaimed space in the transmit ring. | |
3484 | */ | |
3485 | && (free += tulip_tx_intr(sc)) <= 0) { | |
3486 | /* | |
3487 | * There's no more room but since nothing | |
3488 | * has been committed at this point, just | |
3489 | * show output is active, put back the | |
3490 | * mbuf and return. | |
3491 | */ | |
3492 | sc->tulip_flags |= TULIP_WANTTXSTART; | |
3493 | bus_dmamap_unload(ri->ri_data_tag, *eop->di_map); | |
3494 | goto finish; | |
3495 | } | |
3496 | for (; nsegs - segcnt > 1; segcnt += 2) { | |
3497 | eop = nextout; | |
3498 | eop->di_desc->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; | |
3499 | eop->di_desc->d_status = d_status; | |
3500 | eop->di_desc->d_addr1 = segs[segcnt].ds_addr & 0xffffffff; | |
3501 | eop->di_desc->d_length1 = segs[segcnt].ds_len; | |
3502 | eop->di_desc->d_addr2 = segs[segcnt+1].ds_addr & 0xffffffff; | |
3503 | eop->di_desc->d_length2 = segs[segcnt+1].ds_len; | |
3504 | d_status = TULIP_DSTS_OWNER; | |
3505 | if (++nextout == ri->ri_last) | |
3506 | nextout = ri->ri_first; | |
3507 | } | |
3508 | if (segcnt < nsegs) { | |
3509 | eop = nextout; | |
3510 | eop->di_desc->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; | |
3511 | eop->di_desc->d_status = d_status; | |
3512 | eop->di_desc->d_addr1 = segs[segcnt].ds_addr & 0xffffffff; | |
3513 | eop->di_desc->d_length1 = segs[segcnt].ds_len; | |
3514 | eop->di_desc->d_addr2 = 0; | |
3515 | eop->di_desc->d_length2 = 0; | |
3516 | if (++nextout == ri->ri_last) | |
3517 | nextout = ri->ri_first; | |
3518 | } | |
984263bc | 3519 | |
5d2944c2 IV |
3520 | /* |
3521 | * tulip_tx_intr() harvests the mbuf from the last descriptor in the | |
3522 | * frame. We just used the dmamap in the first descriptor for the | |
3523 | * load operation however. Thus, to let the tulip_dequeue_mbuf() call | |
3524 | * in tulip_tx_intr() unload the correct dmamap, we swap the dmamap | |
3525 | * pointers in the two descriptors if this is a multiple-descriptor | |
3526 | * packet. | |
3527 | */ | |
3528 | if (eop != ri->ri_nextout) { | |
3529 | map = eop->di_map; | |
3530 | eop->di_map = ri->ri_nextout->di_map; | |
3531 | ri->ri_nextout->di_map = map; | |
3532 | } | |
3533 | ||
3534 | /* | |
3535 | * bounce a copy to the bpf listener, if any. | |
3536 | */ | |
3537 | if (!(sc->tulip_flags & TULIP_DEVICEPROBE)) | |
3538 | BPF_MTAP(&sc->arpcom.ac_if, m); | |
984263bc MD |
3539 | |
3540 | /* | |
3541 | * The descriptors have been filled in. Now get ready | |
3542 | * to transmit. | |
3543 | */ | |
5d2944c2 IV |
3544 | KASSERT(eop->di_mbuf == NULL, ("clobbering earlier tx mbuf")); |
3545 | eop->di_mbuf = m; | |
3546 | TULIP_TXMAP_PRESYNC(ri, ri->ri_nextout); | |
984263bc MD |
3547 | m = NULL; |
3548 | ||
3549 | /* | |
3550 | * Make sure the next descriptor after this packet is owned | |
3551 | * by us since it may have been set up above if we ran out | |
3552 | * of room in the ring. | |
3553 | */ | |
5d2944c2 IV |
3554 | DESC_STATUS(nextout) = 0; |
3555 | TULIP_TXDESC_PRESYNC(ri); | |
984263bc MD |
3556 | |
3557 | /* | |
3558 | * Mark the last and first segments, indicate we want a transmit | |
3559 | * complete interrupt, and tell it to transmit! | |
3560 | */ | |
5d2944c2 | 3561 | DESC_FLAG(eop) |= TULIP_DFLAG_TxLASTSEG|TULIP_DFLAG_TxWANTINTR; |
984263bc MD |
3562 | |
3563 | /* | |
3564 | * Note that ri->ri_nextout is still the start of the packet | |
3565 | * and until we set the OWNER bit, we can still back out of | |
3566 | * everything we have done. | |
3567 | */ | |
5d2944c2 IV |
3568 | DESC_FLAG(ri->ri_nextout) |= TULIP_DFLAG_TxFIRSTSEG; |
3569 | TULIP_TXDESC_PRESYNC(ri); | |
3570 | DESC_STATUS(ri->ri_nextout) = TULIP_DSTS_OWNER; | |
3571 | TULIP_TXDESC_PRESYNC(ri); | |
984263bc MD |
3572 | |
3573 | /* | |
3574 | * This advances the ring for us. | |
3575 | */ | |
3576 | ri->ri_nextout = nextout; | |
3577 | ri->ri_free = free; | |
3578 | ||
984263bc MD |
3579 | if (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) { |
3580 | TULIP_CSR_WRITE(sc, csr_txpoll, 1); | |
5d2944c2 | 3581 | ifq_set_oactive(&sc->arpcom.ac_if.if_snd); |
984263bc MD |
3582 | return NULL; |
3583 | } | |
3584 | ||
3585 | /* | |
3586 | * switch back to the single queueing ifstart. | |
3587 | */ | |
3588 | sc->tulip_flags &= ~TULIP_WANTTXSTART; | |
3589 | if (sc->tulip_txtimer == 0) | |
5d2944c2 | 3590 | sc->tulip_txtimer = TULIP_TXTIMER; |
984263bc MD |
3591 | |
3592 | /* | |
3593 | * If we want a txstart, there must be not enough space in the | |
3594 | * transmit ring. So we want to enable transmit done interrupts | |
3595 | * so we can immediately reclaim some space. When the transmit | |
3596 | * interrupt is posted, the interrupt handler will call tx_intr | |
3597 | * to reclaim space and then txstart (since WANTTXSTART is set). | |
3598 | * txstart will move the packet into the transmit ring and clear | |
3599 | * WANTTXSTART thereby causing TXINTR to be cleared. | |
3600 | */ | |
3601 | finish: | |
984263bc | 3602 | if (sc->tulip_flags & (TULIP_WANTTXSTART|TULIP_DOINGSETUP)) { |
5d2944c2 | 3603 | ifq_set_oactive(&sc->arpcom.ac_if.if_snd); |
984263bc MD |
3604 | if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) { |
3605 | sc->tulip_intrmask |= TULIP_STS_TXINTR; | |
3606 | TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); | |
3607 | } | |
3608 | } else if ((sc->tulip_flags & TULIP_PROMISC) == 0) { | |
3609 | if (sc->tulip_intrmask & TULIP_STS_TXINTR) { | |
3610 | sc->tulip_intrmask &= ~TULIP_STS_TXINTR; | |
3611 | TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); | |
3612 | } | |
3613 | } | |
3614 | TULIP_CSR_WRITE(sc, csr_txpoll, 1); | |
984263bc MD |
3615 | return m; |
3616 | } | |
79fe23de | 3617 | |
984263bc | 3618 | static void |
79fe23de | 3619 | tulip_txput_setup(tulip_softc_t *sc) |
984263bc | 3620 | { |
79fe23de | 3621 | tulip_ringinfo_t *ri = &sc->tulip_txinfo; |
984263bc MD |
3622 | tulip_desc_t *nextout; |
3623 | ||
3624 | /* | |
3625 | * We will transmit, at most, one setup packet per call to ifstart. | |
3626 | */ | |
3627 | ||
984263bc MD |
3628 | /* |
3629 | * Try to reclaim some free descriptors.. | |
3630 | */ | |
3631 | if (ri->ri_free < 2) | |
3632 | tulip_tx_intr(sc); | |
3633 | if ((sc->tulip_flags & TULIP_DOINGSETUP) || ri->ri_free == 1) { | |
3634 | sc->tulip_flags |= TULIP_WANTTXSTART; | |
984263bc MD |
3635 | return; |
3636 | } | |
3637 | bcopy(sc->tulip_setupdata, sc->tulip_setupbuf, | |
5d2944c2 | 3638 | sizeof(sc->tulip_setupdata)); |
984263bc | 3639 | /* |
5d2944c2 | 3640 | * Clear WANTSETUP and set DOINGSETUP. Since we know that WANTSETUP is |
984263bc MD |
3641 | * set and DOINGSETUP is clear doing an XOR of the two will DTRT. |
3642 | */ | |
3643 | sc->tulip_flags ^= TULIP_WANTSETUP|TULIP_DOINGSETUP; | |
3644 | ri->ri_free--; | |
5d2944c2 | 3645 | nextout = ri->ri_nextout->di_desc; |
984263bc MD |
3646 | nextout->d_flag &= TULIP_DFLAG_ENDRING|TULIP_DFLAG_CHAIN; |
3647 | nextout->d_flag |= TULIP_DFLAG_TxFIRSTSEG|TULIP_DFLAG_TxLASTSEG | |
3648 | |TULIP_DFLAG_TxSETUPPKT|TULIP_DFLAG_TxWANTINTR; | |
3649 | if (sc->tulip_flags & TULIP_WANTHASHPERFECT) | |
3650 | nextout->d_flag |= TULIP_DFLAG_TxHASHFILT; | |
3651 | else if (sc->tulip_flags & TULIP_WANTHASHONLY) | |
3652 | nextout->d_flag |= TULIP_DFLAG_TxHASHFILT|TULIP_DFLAG_TxINVRSFILT; | |
3653 | ||
3654 | nextout->d_length2 = 0; | |
3655 | nextout->d_addr2 = 0; | |
5d2944c2 IV |
3656 | nextout->d_length1 = sizeof(sc->tulip_setupdata); |
3657 | nextout->d_addr1 = sc->tulip_setup_dma_addr & 0xffffffff; | |
3658 | bus_dmamap_sync(sc->tulip_setup_tag, sc->tulip_setup_map, | |
3659 | BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); | |
3660 | TULIP_TXDESC_PRESYNC(ri); | |
984263bc MD |
3661 | |
3662 | /* | |
3663 | * Advance the ring for the next transmit packet. | |
3664 | */ | |
3665 | if (++ri->ri_nextout == ri->ri_last) | |
3666 | ri->ri_nextout = ri->ri_first; | |
3667 | ||
3668 | /* | |
3669 | * Make sure the next descriptor is owned by us since it | |
3670 | * may have been set up above if we ran out of room in the | |
3671 | * ring. | |
3672 | */ | |
5d2944c2 IV |
3673 | DESC_STATUS(ri->ri_nextout) = 0; |
3674 | TULIP_TXDESC_PRESYNC(ri); | |
984263bc MD |
3675 | nextout->d_status = TULIP_DSTS_OWNER; |
3676 | /* | |
3677 | * Flush the ownwership of the current descriptor | |
3678 | */ | |
5d2944c2 | 3679 | TULIP_TXDESC_PRESYNC(ri); |
984263bc MD |
3680 | TULIP_CSR_WRITE(sc, csr_txpoll, 1); |
3681 | if ((sc->tulip_intrmask & TULIP_STS_TXINTR) == 0) { | |
3682 | sc->tulip_intrmask |= TULIP_STS_TXINTR; | |
3683 | TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask); | |
3684 | } | |
3685 | } | |
3686 | ||
984263bc | 3687 | static int |
79fe23de | 3688 | tulip_ifioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred * cr) |
984263bc | 3689 | { |
79fe23de | 3690 | tulip_softc_t *sc = (tulip_softc_t *)ifp->if_softc; |
79fe23de | 3691 | struct ifreq *ifr = (struct ifreq *)data; |
984263bc MD |
3692 | int error = 0; |
3693 | ||
984263bc | 3694 | switch (cmd) { |
984263bc | 3695 | case SIOCGIFADDR: { |
5d2944c2 | 3696 | bcopy((caddr_t) sc->arpcom.ac_enaddr, |
984263bc | 3697 | (caddr_t) ((struct sockaddr *)&ifr->ifr_data)->sa_data, |
5d2944c2 | 3698 | ETHER_ADDR_LEN); |
984263bc MD |
3699 | break; |
3700 | } | |
3701 | ||
3702 | case SIOCSIFFLAGS: { | |
3703 | tulip_addr_filter(sc); /* reinit multicast filter */ | |
3704 | tulip_init(sc); | |
3705 | break; | |
3706 | } | |
3707 | ||
3708 | case SIOCSIFMEDIA: | |
3709 | case SIOCGIFMEDIA: { | |
3710 | error = ifmedia_ioctl(ifp, ifr, &sc->tulip_ifmedia, cmd); | |
3711 | break; | |
3712 | } | |
3713 | ||
3714 | case SIOCADDMULTI: | |
3715 | case SIOCDELMULTI: { | |
3716 | /* | |
3717 | * Update multicast listeners | |
3718 | */ | |
3719 | tulip_addr_filter(sc); /* reset multicast filtering */ | |
3720 | tulip_init(sc); | |
3721 | error = 0; | |
3722 | break; | |
3723 | } | |
3724 | ||
3725 | case SIOCSIFMTU: | |
3726 | /* | |
3727 | * Set the interface MTU. | |
3728 | */ | |
3729 | if (ifr->ifr_mtu > ETHERMTU | |
984263bc MD |
3730 | ) { |
3731 | error = EINVAL; | |
3732 | break; | |
3733 | } | |
3734 | ifp->if_mtu = ifr->ifr_mtu; | |
984263bc MD |
3735 | break; |
3736 | ||
3737 | #ifdef SIOCGADDRROM | |
3738 | case SIOCGADDRROM: { | |
3739 | error = copyout(sc->tulip_rombuf, ifr->ifr_data, sizeof(sc->tulip_rombuf)); | |
3740 | break; | |
3741 | } | |
3742 | #endif | |
3743 | #ifdef SIOCGCHIPID | |
3744 | case SIOCGCHIPID: { | |
3745 | ifr->ifr_metric = (int) sc->tulip_chipid; | |
3746 | break; | |
3747 | } | |
3748 | #endif | |
3749 | default: { | |
1267e20a | 3750 | error = ether_ioctl(ifp, cmd, data); |
984263bc MD |
3751 | break; |
3752 | } | |
3753 | } | |
984263bc MD |
3754 | return error; |
3755 | } | |
79fe23de | 3756 | |
a5898a47 SZ |
3757 | static void |
3758 | tulip_ifinit(void *xsc) | |
3759 | { | |
3760 | tulip_softc_t *sc = xsc; | |
3761 | ||
3762 | tulip_addr_filter(sc); /* reinit multicast filter */ | |
3763 | tulip_init(sc); | |
3764 | } | |
3765 | ||
984263bc | 3766 | static void |
f0a26983 | 3767 | tulip_ifstart(struct ifnet *ifp, struct ifaltq_subque *ifsq) |
984263bc | 3768 | { |
79fe23de | 3769 | tulip_softc_t *sc = (tulip_softc_t *)ifp->if_softc; |
984263bc | 3770 | |
f0a26983 | 3771 | ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq); |
5d2944c2 | 3772 | if (sc->arpcom.ac_if.if_flags & IFF_RUNNING) { |
984263bc MD |
3773 | |
3774 | if ((sc->tulip_flags & (TULIP_WANTSETUP|TULIP_TXPROBE_ACTIVE)) == TULIP_WANTSETUP) | |
3775 | tulip_txput_setup(sc); | |
3776 | ||
5d2944c2 | 3777 | while (!ifq_is_empty(&sc->arpcom.ac_if.if_snd)) { |
984263bc | 3778 | struct mbuf *m; |
9db4b353 | 3779 | |
5d2944c2 | 3780 | m = ifq_dequeue(&sc->arpcom.ac_if.if_snd); |
23f8872b SZ |
3781 | if (m == NULL) |
3782 | break; | |
9db4b353 | 3783 | |
984263bc | 3784 | if ((m = tulip_txput(sc, m)) != NULL) { |
5d2944c2 | 3785 | ifq_prepend(&sc->arpcom.ac_if.if_snd, m); |
984263bc MD |
3786 | break; |
3787 | } | |
3788 | } | |
984263bc | 3789 | } |
984263bc | 3790 | } |
79fe23de | 3791 | |
984263bc | 3792 | static void |
79fe23de | 3793 | tulip_ifwatchdog(struct ifnet *ifp) |
984263bc | 3794 | { |
984263bc MD |
3795 | tulip_softc_t * const sc = (tulip_softc_t *)ifp->if_softc; |
3796 | ||
5d2944c2 | 3797 | sc->arpcom.ac_if.if_timer = 1; |
984263bc MD |
3798 | /* |
3799 | * These should be rare so do a bulk test up front so we can just skip | |
3800 | * them if needed. | |
3801 | */ | |
3802 | if (sc->tulip_flags & (TULIP_SYSTEMERROR|TULIP_RXBUFSLOW|TULIP_NOMESSAGES)) { | |
3803 | /* | |
3804 | * If the number of receive buffer is low, try to refill | |
3805 | */ | |
3806 | if (sc->tulip_flags & TULIP_RXBUFSLOW) | |
3807 | tulip_rx_intr(sc); | |
3808 | ||
3809 | if (sc->tulip_flags & TULIP_SYSTEMERROR) { | |
b3e6c01b JS |
3810 | if_printf(ifp, "%d system errors: last was %s\n", |
3811 | sc->tulip_system_errors, | |
3812 | tulip_system_errors[sc->tulip_last_system_error]); | |
984263bc MD |
3813 | } |
3814 | if (sc->tulip_statusbits) { | |
3815 | tulip_print_abnormal_interrupt(sc, sc->tulip_statusbits); | |
3816 | sc->tulip_statusbits = 0; | |
3817 | } | |
3818 | ||
3819 | sc->tulip_flags &= ~(TULIP_NOMESSAGES|TULIP_SYSTEMERROR); | |
3820 | } | |
3821 | ||
3822 | if (sc->tulip_txtimer) | |
3823 | tulip_tx_intr(sc); | |
3824 | if (sc->tulip_txtimer && --sc->tulip_txtimer == 0) { | |
b3e6c01b | 3825 | if_printf(ifp, "transmission timeout\n"); |
984263bc MD |
3826 | if (TULIP_DO_AUTOSENSE(sc)) { |
3827 | sc->tulip_media = TULIP_MEDIA_UNKNOWN; | |
3828 | sc->tulip_probe_state = TULIP_PROBE_INACTIVE; | |
3829 | sc->tulip_flags &= ~(TULIP_WANTRXACT|TULIP_LINKUP); | |
3830 | } | |
3831 | tulip_reset(sc); | |
3832 | tulip_init(sc); | |
3833 | } | |
984263bc | 3834 | } |
984263bc MD |
3835 | |
3836 | static void | |
79fe23de | 3837 | tulip_attach(tulip_softc_t *sc) |
984263bc | 3838 | { |
5d2944c2 | 3839 | struct ifnet *ifp = &sc->arpcom.ac_if; |
88fcae56 | 3840 | |
984263bc | 3841 | ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST; |
a5898a47 | 3842 | ifp->if_init = tulip_ifinit; |
984263bc MD |
3843 | ifp->if_ioctl = tulip_ifioctl; |
3844 | ifp->if_start = tulip_ifstart; | |
3845 | ifp->if_watchdog = tulip_ifwatchdog; | |
3846 | ifp->if_timer = 1; | |
984263bc | 3847 | |
b3e6c01b | 3848 | if_printf(ifp, "%s%s pass %d.%d%s\n", |
984263bc MD |
3849 | sc->tulip_boardid, |
3850 | tulip_chipdescs[sc->tulip_chipid], | |
3851 | (sc->tulip_revinfo & 0xF0) >> 4, | |
3852 | sc->tulip_revinfo & 0x0F, | |
3853 | (sc->tulip_features & (TULIP_HAVE_ISVSROM|TULIP_HAVE_OKSROM)) | |
3854 | == TULIP_HAVE_ISVSROM ? " (invalid EESPROM checksum)" : ""); | |
984263bc | 3855 | |
984263bc MD |
3856 | (*sc->tulip_boardsw->bd_media_probe)(sc); |
3857 | ifmedia_init(&sc->tulip_ifmedia, 0, | |
3858 | tulip_ifmedia_change, | |
3859 | tulip_ifmedia_status); | |
3860 | sc->tulip_flags &= ~TULIP_DEVICEPROBE; | |
3861 | tulip_ifmedia_add(sc); | |
3862 | ||
ef9870ec | 3863 | ifq_set_maxlen(&ifp->if_snd, ifqmaxlen); |
5d2944c2 | 3864 | ether_ifattach(&sc->arpcom.ac_if, sc->arpcom.ac_enaddr, NULL); |
69d29553 SZ |
3865 | |
3866 | tulip_reset(sc); | |
984263bc | 3867 | } |
79fe23de | 3868 | |
5d2944c2 | 3869 | /* Release memory for a single descriptor ring. */ |
81b5c339 | 3870 | static void |
5d2944c2 | 3871 | tulip_busdma_freering(tulip_ringinfo_t *ri) |
81b5c339 | 3872 | { |
5d2944c2 IV |
3873 | int i; |
3874 | ||
3875 | /* Release the DMA maps and tag for data buffers. */ | |
3876 | if (ri->ri_data_maps != NULL) { | |
3877 | for (i = 0; i < ri->ri_max; i++) { | |
3878 | if (ri->ri_data_maps[i] != NULL) { | |
3879 | bus_dmamap_destroy(ri->ri_data_tag, ri->ri_data_maps[i]); | |
3880 | ri->ri_data_maps[i] = NULL; | |
3881 | } | |
3882 | } | |
3883 | kfree(ri->ri_data_maps, M_DEVBUF); | |
3884 | ri->ri_data_maps = NULL; | |
3885 | } | |
3886 | if (ri->ri_data_tag != NULL) { | |
3887 | bus_dma_tag_destroy(ri->ri_data_tag); | |
3888 | ri->ri_data_tag = NULL; | |
3889 | } | |
3890 | ||
3891 | /* Release the DMA memory and tag for the ring descriptors. */ | |
3892 | if (ri->ri_dma_addr != 0) { | |
3893 | bus_dmamap_unload(ri->ri_ring_tag, ri->ri_ring_map); | |
3894 | ri->ri_dma_addr = 0; | |
3895 | } | |
3896 | if (ri->ri_descs != NULL) { | |
3897 | bus_dmamem_free(ri->ri_ring_tag, ri->ri_descs, ri->ri_ring_map); | |
3898 | ri->ri_descs = NULL; | |
3899 | } | |
3900 | if (ri->ri_ring_tag != NULL) { | |
3901 | bus_dma_tag_destroy(ri->ri_ring_tag); | |
3902 | ri->ri_ring_tag = NULL; | |
3903 | } | |
3904 | } | |
3905 | ||
3906 | /* Allocate memory for a single descriptor ring. */ | |
3907 | static int | |
3908 | tulip_busdma_allocring(device_t dev, tulip_softc_t *sc, size_t count, | |
3909 | bus_size_t align, int nsegs, tulip_ringinfo_t *ri, const char *name) | |
3910 | { | |
3911 | size_t size; | |
3912 | int error, i; | |
3913 | ||
3914 | /* First, setup a tag. */ | |
3915 | ri->ri_max = count; | |
3916 | size = count * sizeof(tulip_desc_t); | |
3917 | error = bus_dma_tag_create(bus_get_dma_tag(dev), | |
3918 | 32, 0, BUS_SPACE_MAXADDR_32BIT, | |
030b0c8c | 3919 | BUS_SPACE_MAXADDR, size, 1, size, 0, &ri->ri_ring_tag); |
5d2944c2 IV |
3920 | if (error) { |
3921 | device_printf(dev, "failed to allocate %s descriptor ring dma tag\n", | |
3922 | name); | |
3923 | return (error); | |
3924 | } | |
3925 | ||
3926 | /* Next, allocate memory for the descriptors. */ | |
3927 | error = bus_dmamem_alloc(ri->ri_ring_tag, (void **)&ri->ri_descs, | |
3928 | BUS_DMA_NOWAIT | BUS_DMA_ZERO, &ri->ri_ring_map); | |
3929 | if (error) { | |
3930 | device_printf(dev, "failed to allocate memory for %s descriptor ring\n", | |
3931 | name); | |
3932 | return (error); | |
3933 | } | |
3934 | ||
3935 | /* Map the descriptors. */ | |
3936 | error = bus_dmamap_load(ri->ri_ring_tag, ri->ri_ring_map, ri->ri_descs, | |
3937 | size, tulip_dma_map_addr, &ri->ri_dma_addr, BUS_DMA_NOWAIT); | |
3938 | if (error) { | |
3939 | device_printf(dev, "failed to get dma address for %s descriptor ring\n", | |
3940 | name); | |
3941 | return (error); | |
3942 | } | |
3943 | ||
3944 | /* Allocate a tag for the data buffers. */ | |
3945 | error = bus_dma_tag_create(bus_get_dma_tag(dev), align, 0, | |
030b0c8c | 3946 | BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, |
5d2944c2 IV |
3947 | MCLBYTES * nsegs, nsegs, MCLBYTES, 0, &ri->ri_data_tag); |
3948 | if (error) { | |
3949 | device_printf(dev, "failed to allocate %s buffer dma tag\n", name); | |
3950 | return (error); | |
3951 | } | |
3952 | ||
3953 | /* Allocate maps for the data buffers. */ | |
3954 | ri->ri_data_maps = kmalloc(sizeof(bus_dmamap_t) * count, M_DEVBUF, | |
3955 | M_WAITOK | M_ZERO); | |
3956 | for (i = 0; i < count; i++) { | |
3957 | error = bus_dmamap_create(ri->ri_data_tag, 0, &ri->ri_data_maps[i]); | |
3958 | if (error) { | |
3959 | device_printf(dev, "failed to create map for %s buffer %d\n", | |
3960 | name, i); | |
3961 | return (error); | |
3962 | } | |
3963 | } | |
3964 | ||
3965 | return (0); | |
3966 | } | |
3967 | ||
3968 | /* Release busdma maps, tags, and memory. */ | |
3969 | static void | |
3970 | tulip_busdma_cleanup(tulip_softc_t *sc) | |
3971 | { | |
3972 | ||
3973 | /* Release resources for the setup descriptor. */ | |
3974 | if (sc->tulip_setup_dma_addr != 0) { | |
3975 | bus_dmamap_unload(sc->tulip_setup_tag, sc->tulip_setup_map); | |
3976 | sc->tulip_setup_dma_addr = 0; | |
3977 | } | |
3978 | if (sc->tulip_setupbuf != NULL) { | |
3979 | bus_dmamem_free(sc->tulip_setup_tag, sc->tulip_setupbuf, | |
3980 | sc->tulip_setup_map); | |
3981 | sc->tulip_setupbuf = NULL; | |
3982 | } | |
3983 | if (sc->tulip_setup_tag != NULL) { | |
3984 | bus_dma_tag_destroy(sc->tulip_setup_tag); | |
3985 | sc->tulip_setup_tag = NULL; | |
3986 | } | |
3987 | ||
3988 | /* Release the transmit ring. */ | |
3989 | tulip_busdma_freering(&sc->tulip_txinfo); | |
3990 | ||
3991 | /* Release the receive ring. */ | |
3992 | tulip_busdma_freering(&sc->tulip_rxinfo); | |
3993 | } | |
3994 | ||
3995 | static int | |
3996 | tulip_busdma_init(device_t dev, tulip_softc_t *sc) | |
3997 | { | |
3998 | int error; | |
3999 | ||
4000 | /* | |
4001 | * Allocate space and dmamap for transmit ring. | |
4002 | */ | |
4003 | error = tulip_busdma_allocring(dev, sc, TULIP_TXDESCS, 1, TULIP_MAX_TXSEG, | |
4004 | &sc->tulip_txinfo, "transmit"); | |
4005 | if (error) | |
4006 | return (error); | |
4007 | ||
4008 | /* | |
4009 | * Allocate space and dmamap for receive ring. We tell bus_dma that | |
4010 | * we can map MCLBYTES so that it will accept a full MCLBYTES cluster, | |
4011 | * but we will only map the first TULIP_RX_BUFLEN bytes. This is not | |
4012 | * a waste in practice though as an ethernet frame can easily fit | |
4013 | * in TULIP_RX_BUFLEN bytes. | |
4014 | */ | |
4015 | error = tulip_busdma_allocring(dev, sc, TULIP_RXDESCS, 4, 1, | |
4016 | &sc->tulip_rxinfo, "receive"); | |
4017 | if (error) | |
4018 | return (error); | |
4019 | ||
4020 | /* | |
4021 | * Allocate a DMA tag, memory, and map for setup descriptor | |
4022 | */ | |
4023 | error = bus_dma_tag_create(bus_get_dma_tag(dev), 32, 0, | |
030b0c8c | 4024 | BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, |
5d2944c2 IV |
4025 | sizeof(sc->tulip_setupdata), 1, sizeof(sc->tulip_setupdata), 0, |
4026 | &sc->tulip_setup_tag); | |
4027 | if (error) { | |
4028 | device_printf(dev, "failed to allocate setup descriptor dma tag\n"); | |
4029 | return (error); | |
4030 | } | |
4031 | error = bus_dmamem_alloc(sc->tulip_setup_tag, (void **)&sc->tulip_setupbuf, | |
4032 | BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sc->tulip_setup_map); | |
4033 | if (error) { | |
4034 | device_printf(dev, "failed to allocate memory for setup descriptor\n"); | |
4035 | return (error); | |
4036 | } | |
4037 | error = bus_dmamap_load(sc->tulip_setup_tag, sc->tulip_setup_map, | |
4038 | sc->tulip_setupbuf, sizeof(sc->tulip_setupdata), | |
4039 | tulip_dma_map_addr, &sc->tulip_setup_dma_addr, BUS_DMA_NOWAIT); | |
4040 | if (error) { | |
4041 | device_printf(dev, "failed to get dma address for setup descriptor\n"); | |
4042 | return (error); | |
4043 | } | |
4044 | ||
4045 | return error; | |
81b5c339 MD |
4046 | } |
4047 | ||
984263bc | 4048 | static void |
79fe23de | 4049 | tulip_initcsrs(tulip_softc_t *sc, tulip_csrptr_t csr_base, size_t csr_size) |
984263bc MD |
4050 | { |
4051 | sc->tulip_csrs.csr_busmode = csr_base + 0 * csr_size; | |
4052 | sc->tulip_csrs.csr_txpoll = csr_base + 1 * csr_size; | |
4053 | sc->tulip_csrs.csr_rxpoll = csr_base + 2 * csr_size; | |
4054 | sc->tulip_csrs.csr_rxlist = csr_base + 3 * csr_size; | |
4055 | sc->tulip_csrs.csr_txlist = csr_base + 4 * csr_size; | |
4056 | sc->tulip_csrs.csr_status = csr_base + 5 * csr_size; | |
4057 | sc->tulip_csrs.csr_command = csr_base + 6 * csr_size; | |
4058 | sc->tulip_csrs.csr_intr = csr_base + 7 * csr_size; | |
4059 | sc->tulip_csrs.csr_missed_frames = csr_base + 8 * csr_size; | |
4060 | sc->tulip_csrs.csr_9 = csr_base + 9 * csr_size; | |
4061 | sc->tulip_csrs.csr_10 = csr_base + 10 * csr_size; | |
4062 | sc->tulip_csrs.csr_11 = csr_base + 11 * csr_size; | |
4063 | sc->tulip_csrs.csr_12 = csr_base + 12 * csr_size; | |
4064 | sc->tulip_csrs.csr_13 = csr_base + 13 * csr_size; | |
4065 | sc->tulip_csrs.csr_14 = csr_base + 14 * csr_size; | |
4066 | sc->tulip_csrs.csr_15 = csr_base + 15 * csr_size; | |
4067 | } | |
79fe23de | 4068 | |
5d2944c2 IV |
4069 | static int |
4070 | tulip_initring(tulip_ringinfo_t *ri, int ndescs) | |
984263bc | 4071 | { |
5d2944c2 IV |
4072 | int i; |
4073 | ||
4074 | ri->ri_descinfo = kmalloc(sizeof(tulip_descinfo_t) * ndescs, M_DEVBUF, | |
4075 | M_WAITOK | M_ZERO); | |
4076 | for (i = 0; i < ndescs; i++) { | |
4077 | ri->ri_descinfo[i].di_desc = &ri->ri_descs[i]; | |
4078 | ri->ri_descinfo[i].di_map = &ri->ri_data_maps[i]; | |
4079 | } | |
4080 | ri->ri_first = ri->ri_descinfo; | |
984263bc | 4081 | ri->ri_max = ndescs; |
984263bc | 4082 | ri->ri_last = ri->ri_first + ri->ri_max; |
5d2944c2 IV |
4083 | bzero(ri->ri_descs, sizeof(tulip_desc_t) * ri->ri_max); |
4084 | DESC_FLAG(&ri->ri_last[-1]) = TULIP_DFLAG_ENDRING; | |
4085 | return (0); | |
984263bc | 4086 | } |
79fe23de | 4087 | |
984263bc MD |
4088 | /* |
4089 | * This is the PCI configuration support. | |
4090 | */ | |
4091 | ||
5d2944c2 IV |
4092 | #define PCI_CBIO PCIR_BAR(0) /* Configuration Base IO Address */ |
4093 | #define PCI_CBMA PCIR_BAR(1) /* Configuration Base Memory Address */ | |
984263bc MD |
4094 | #define PCI_CFDA 0x40 /* Configuration Driver Area */ |
4095 | ||
4096 | static int | |
4097 | tulip_pci_probe(device_t dev) | |
4098 | { | |
4099 | const char *name = NULL; | |
4100 | ||
4101 | if (pci_get_vendor(dev) != DEC_VENDORID) | |
4102 | return ENXIO; | |
4103 | ||
4104 | /* | |
4105 | * Some LanMedia WAN cards use the Tulip chip, but they have | |
4106 | * their own driver, and we should not recognize them | |
4107 | */ | |
4108 | if (pci_get_subvendor(dev) == 0x1376) | |
4109 | return ENXIO; | |
4110 | ||
4111 | switch (pci_get_device(dev)) { | |
4112 | case CHIPID_21040: | |
4113 | name = "Digital 21040 Ethernet"; | |
4114 | break; | |
4115 | case CHIPID_21041: | |
4116 | name = "Digital 21041 Ethernet"; | |
4117 | break; | |
4118 | case CHIPID_21140: | |
4119 | if (pci_get_revid(dev) >= 0x20) | |
4120 | name = "Digital 21140A Fast Ethernet"; | |
4121 | else | |
4122 | name = "Digital 21140 Fast Ethernet"; | |
4123 | break; | |
4124 | case CHIPID_21142: | |
4125 | if (pci_get_revid(dev) >= 0x20) | |
4126 | name = "Digital 21143 Fast Ethernet"; | |
4127 | else | |
4128 | name = "Digital 21142 Fast Ethernet"; | |
4129 | break; | |
4130 | } | |
4131 | if (name) { | |
4132 | device_set_desc(dev, name); | |
4133 | return -200; | |
4134 | } | |
4135 | return ENXIO; | |
4136 | } | |
4137 | ||
4138 | static int | |
4139 | tulip_shutdown(device_t dev) | |
4140 | { | |
79fe23de | 4141 | tulip_softc_t *sc = device_get_softc(dev); |
78195a76 | 4142 | |
5d2944c2 | 4143 | lwkt_serialize_enter(sc->arpcom.ac_if.if_serializer); |
984263bc MD |
4144 | TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); |
4145 | DELAY(10); /* Wait 10 microseconds (actually 50 PCI cycles but at | |
4146 | 33MHz that comes to two microseconds but wait a | |
4147 | bit longer anyways) */ | |
5d2944c2 | 4148 | lwkt_serialize_exit(sc->arpcom.ac_if.if_serializer); |
984263bc MD |
4149 | return 0; |
4150 | } | |
4151 | ||
4152 | static int | |
4153 | tulip_pci_attach(device_t dev) | |
4154 | { | |
4155 | tulip_softc_t *sc; | |
984263bc | 4156 | int retval, idx; |
9929b827 | 4157 | uint32_t revinfo, cfdainfo; |
79fe23de JS |
4158 | u_int csroffset = TULIP_PCI_CSROFFSET; |
4159 | u_int csrsize = TULIP_PCI_CSRSIZE; | |
984263bc MD |
4160 | tulip_csrptr_t csr_base; |
4161 | tulip_chipid_t chipid = TULIP_CHIPID_UNKNOWN; | |
4162 | struct resource *res; | |
5d2944c2 | 4163 | int rid, unit; |
984263bc | 4164 | |
5d2944c2 IV |
4165 | unit = device_get_unit(dev); |
4166 | ||
4167 | if (unit >= TULIP_MAX_DEVICES) { | |
b3e6c01b | 4168 | device_printf(dev, "not configured; limit of %d reached or exceeded\n", |
984263bc MD |
4169 | TULIP_MAX_DEVICES); |
4170 | return ENXIO; | |
4171 | } | |
4172 | ||
4173 | revinfo = pci_get_revid(dev); | |
4174 | cfdainfo = pci_read_config(dev, PCI_CFDA, 4); | |
984263bc MD |
4175 | |
4176 | /* turn busmaster on in case BIOS doesn't set it */ | |
79fe23de | 4177 | pci_enable_busmaster(dev); |
984263bc MD |
4178 | |
4179 | if (pci_get_vendor(dev) == DEC_VENDORID) { | |
4180 | if (pci_get_device(dev) == CHIPID_21040) | |
4181 | chipid = TULIP_21040; | |
4182 | else if (pci_get_device(dev) == CHIPID_21041) | |
4183 | chipid = TULIP_21041; | |
4184 | else if (pci_get_device(dev) == CHIPID_21140) | |
4185 | chipid = (revinfo >= 0x20) ? TULIP_21140A : TULIP_21140; | |
4186 | else if (pci_get_device(dev) == CHIPID_21142) | |
4187 | chipid = (revinfo >= 0x20) ? TULIP_21143 : TULIP_21142; | |
4188 | } | |
4189 | if (chipid == TULIP_CHIPID_UNKNOWN) | |
4190 | return ENXIO; | |
4191 | ||
4192 | if (chipid == TULIP_21040 && revinfo < 0x20) { | |
5d2944c2 IV |
4193 | device_printf(dev, |
4194 | "not configured; 21040 pass 2.0 required (%d.%d found)\n", | |
4195 | revinfo >> 4, revinfo & 0x0f); | |
984263bc MD |
4196 | return ENXIO; |
4197 | } else if (chipid == TULIP_21140 && revinfo < 0x11) { | |
5d2944c2 IV |
4198 | device_printf(dev, |
4199 | "not configured; 21140 pass 1.1 required (%d.%d found)\n", | |
4200 | revinfo >> 4, revinfo & 0x0f); | |
984263bc MD |
4201 | return ENXIO; |
4202 | } | |
4203 | ||
4204 | sc = device_get_softc(dev); | |
b3e6c01b | 4205 | sc->tulip_dev = dev; |
984263bc MD |
4206 | sc->tulip_pci_busno = pci_get_bus(dev); |
4207 | sc->tulip_pci_devno = pci_get_slot(dev); | |
4208 | sc->tulip_chipid = chipid; | |
4209 | sc->tulip_flags |= TULIP_DEVICEPROBE; | |
4210 | if (chipid == TULIP_21140 || chipid == TULIP_21140A) | |
4211 | sc->tulip_features |= TULIP_HAVE_GPR|TULIP_HAVE_STOREFWD; | |
4212 | if (chipid == TULIP_21140A && revinfo <= 0x22) | |
4213 | sc->tulip_features |= TULIP_HAVE_RXBADOVRFLW; | |
4214 | if (chipid == TULIP_21140) | |
4215 | sc->tulip_features |= TULIP_HAVE_BROKEN_HASH; | |
4216 | if (chipid != TULIP_21040 && chipid != TULIP_21140) | |
4217 | sc->tulip_features |= TULIP_HAVE_POWERMGMT; | |
4218 | if (chipid == TULIP_21041 || chipid == TULIP_21142 || chipid == TULIP_21143) { | |
4219 | sc->tulip_features |= TULIP_HAVE_DUALSENSE; | |
4220 | if (chipid != TULIP_21041 || revinfo >= 0x20) | |
4221 | sc->tulip_features |= TULIP_HAVE_SIANWAY; | |
4222 | if (chipid != TULIP_21041) | |
4223 | sc->tulip_features |= TULIP_HAVE_SIAGP|TULIP_HAVE_RXBADOVRFLW|TULIP_HAVE_STOREFWD; | |
4224 | if (chipid != TULIP_21041 && revinfo >= 0x20) | |
4225 | sc->tulip_features |= TULIP_HAVE_SIA100; | |
4226 | } | |
4227 | ||
4228 | if (sc->tulip_features & TULIP_HAVE_POWERMGMT | |
4229 | && (cfdainfo & (TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE))) { | |
4230 | cfdainfo &= ~(TULIP_CFDA_SLEEP|TULIP_CFDA_SNOOZE); | |
4231 | pci_write_config(dev, PCI_CFDA, cfdainfo, 4); | |
4232 | DELAY(11*1000); | |
4233 | } | |
5d2944c2 IV |
4234 | if_initname(&sc->arpcom.ac_if, device_get_name(dev), unit); |
4235 | sc->tulip_unit = unit; | |
984263bc | 4236 | sc->tulip_revinfo = revinfo; |
5d2944c2 | 4237 | sc->arpcom.ac_if.if_softc = sc; |
984263bc MD |
4238 | #if defined(TULIP_IOMAPPED) |
4239 | rid = PCI_CBIO; | |
4e6d744d | 4240 | res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); |
984263bc MD |
4241 | #else |
4242 | rid = PCI_CBMA; | |
4e6d744d | 4243 | res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); |
984263bc MD |
4244 | #endif |
4245 | if (!res) | |
4246 | return ENXIO; | |
4247 | sc->tulip_csrs_bst = rman_get_bustag(res); | |
4248 | sc->tulip_csrs_bsh = rman_get_bushandle(res); | |
4249 | csr_base = 0; | |
4250 | ||
5d2944c2 IV |
4251 | callout_init(&sc->tulip_callout); |
4252 | tulips[unit] = sc; | |
984263bc MD |
4253 | |
4254 | tulip_initcsrs(sc, csr_base + csroffset, csrsize); | |
4255 | ||
5d2944c2 IV |
4256 | if ((retval = tulip_busdma_init(dev, sc)) != 0) { |
4257 | device_printf(dev, "error initing bus_dma: %d\n", retval); | |
4258 | tulip_busdma_cleanup(sc); | |
4259 | return ENXIO; | |
4260 | } | |
984263bc | 4261 | |
5d2944c2 IV |
4262 | retval = tulip_initring(&sc->tulip_rxinfo, TULIP_RXDESCS); |
4263 | if (retval == 0) | |
4264 | retval = tulip_initring(&sc->tulip_txinfo, TULIP_TXDESCS); | |
4265 | if (retval) { | |
4266 | tulip_busdma_cleanup(sc); | |
4267 | return retval; | |
4268 | } | |
984263bc MD |
4269 | |
4270 | /* | |
4271 | * Make sure there won't be any interrupts or such... | |
4272 | */ | |
4273 | TULIP_CSR_WRITE(sc, csr_busmode, TULIP_BUSMODE_SWRESET); | |
4274 | DELAY(100); /* Wait 10 microseconds (actually 50 PCI cycles but at | |
4275 | 33MHz that comes to two microseconds but wait a | |
4276 | bit longer anyways) */ | |
4277 | ||
4278 | if ((retval = tulip_read_macaddr(sc)) < 0) { | |
b3e6c01b | 4279 | device_printf(dev, "can't read ENET ROM (why=%d) (", retval); |
984263bc | 4280 | for (idx = 0; idx < 32; idx++) |
e3869ec7 SW |
4281 | kprintf("%02x", sc->tulip_rombuf[idx]); |
4282 | kprintf("\n"); | |
b3e6c01b | 4283 | device_printf(dev, "%s%s pass %d.%d\n", |
984263bc MD |
4284 | sc->tulip_boardid, tulip_chipdescs[sc->tulip_chipid], |
4285 | (sc->tulip_revinfo & 0xF0) >> 4, sc->tulip_revinfo & 0x0F); | |
682ba47c | 4286 | device_printf(dev, "address unknown\n"); |
984263bc | 4287 | } else { |
984263bc MD |
4288 | void (*intr_rtn)(void *) = tulip_intr_normal; |
4289 | ||
4290 | if (sc->tulip_features & TULIP_HAVE_SHAREDINTR) | |
4291 | intr_rtn = tulip_intr_shared; | |
4292 | ||
81b5c339 | 4293 | tulip_attach(sc); |
5d2944c2 IV |
4294 | |
4295 | /* Setup interrupt last. */ | |
984263bc MD |
4296 | if ((sc->tulip_features & TULIP_HAVE_SLAVEDINTR) == 0) { |
4297 | void *ih; | |
4298 | ||
4299 | rid = 0; | |
4e6d744d JS |
4300 | res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, |
4301 | RF_SHAREABLE | RF_ACTIVE); | |
4090d6ff | 4302 | if (res == NULL || bus_setup_intr(dev, res, INTR_MPSAFE, |
78195a76 | 4303 | intr_rtn, sc, &ih, |
5d2944c2 | 4304 | sc->arpcom.ac_if.if_serializer)) { |
b3e6c01b | 4305 | device_printf(dev, "couldn't map interrupt\n"); |
5d2944c2 IV |
4306 | ifmedia_removeall(&sc->tulip_ifmedia); |
4307 | ether_ifdetach(&sc->arpcom.ac_if); | |
4308 | tulip_busdma_cleanup(sc); | |
984263bc MD |
4309 | return ENXIO; |
4310 | } | |
9db4b353 | 4311 | |
5d2944c2 | 4312 | ifq_set_cpuid(&sc->arpcom.ac_if.if_snd, rman_get_cpuid(res)); |
984263bc | 4313 | } |
984263bc MD |
4314 | } |
4315 | return 0; | |
4316 | } | |
4317 | ||
4318 | static device_method_t tulip_pci_methods[] = { | |
4319 | /* Device interface */ | |
4320 | DEVMETHOD(device_probe, tulip_pci_probe), | |
4321 | DEVMETHOD(device_attach, tulip_pci_attach), | |
4322 | DEVMETHOD(device_shutdown, tulip_shutdown), | |
d3c9c58e | 4323 | DEVMETHOD_END |
984263bc MD |
4324 | }; |
4325 | static driver_t tulip_pci_driver = { | |
4326 | "de", | |
4327 | tulip_pci_methods, | |
4328 | sizeof(tulip_softc_t), | |
4329 | }; | |
4330 | static devclass_t tulip_devclass; | |
32832096 MD |
4331 | |
4332 | DECLARE_DUMMY_MODULE(if_de); | |
aa2b9d05 | 4333 | DRIVER_MODULE(if_de, pci, tulip_pci_driver, tulip_devclass, NULL, NULL); |
32832096 | 4334 |