if_ae_nubus.c revision 1.9 1 /* $NetBSD: if_ae_nubus.c,v 1.9 1997/03/17 20:26:01 scottr Exp $ */
2
3 /*
4 * Copyright (C) 1997 Scott Reynolds
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Scott Reynolds for
18 * the NetBSD Project.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <sys/param.h>
35 #include <sys/device.h>
36 #include <sys/errno.h>
37 #include <sys/ioctl.h>
38 #include <sys/socket.h>
39 #include <sys/syslog.h>
40 #include <sys/systm.h>
41
42 #include <net/if.h>
43 #include <net/if_ether.h>
44
45 #ifdef INET
46 #include <netinet/in.h>
47 #include <netinet/if_inarp.h>
48 #endif
49
50 #include <machine/bus.h>
51 #include <machine/viareg.h>
52
53 #include "nubus.h"
54 #include <dev/ic/dp8390reg.h>
55 #include "if_aereg.h"
56 #include "if_aevar.h"
57
58 static int ae_nubus_match __P((struct device *, struct cfdata *, void *));
59 static void ae_nubus_attach __P((struct device *, struct device *, void *));
60 static int ae_nb_card_vendor __P((struct nubus_attach_args *));
61 static int ae_nb_get_enaddr __P((struct nubus_attach_args *, u_int8_t *));
62 static void ae_nb_watchdog __P((struct ifnet *));
63
64 struct cfattach ae_nubus_ca = {
65 sizeof(struct ae_softc), ae_nubus_match, ae_nubus_attach
66 };
67
68 static int
69 ae_nubus_match(parent, cf, aux)
70 struct device *parent;
71 struct cfdata *cf;
72 void *aux;
73 {
74 struct nubus_attach_args *na = (struct nubus_attach_args *) aux;
75 bus_space_handle_t bsh;
76 int rv;
77
78 if (bus_space_map(na->na_tag, NUBUS_SLOT2PA(na->slot), NBMEMSIZE,
79 0, &bsh))
80 return (0);
81
82 rv = 0;
83
84 if (na->category == NUBUS_CATEGORY_NETWORK &&
85 na->type == NUBUS_TYPE_ETHERNET) {
86 switch (ae_nb_card_vendor(na)) {
87 case AE_VENDOR_APPLE:
88 case AE_VENDOR_ASANTE:
89 case AE_VENDOR_FARALLON:
90 case AE_VENDOR_INTERLAN:
91 case AE_VENDOR_KINETICS:
92 rv = 1;
93 break;
94 case AE_VENDOR_DAYNA:
95 case AE_VENDOR_FOCUS:
96 rv = UNSUPP;
97 break;
98 default:
99 break;
100 }
101 }
102
103 bus_space_unmap(na->na_tag, bsh, NBMEMSIZE);
104
105 return rv;
106 }
107
108 /*
109 * Install interface into kernel networking data structures
110 */
111 static void
112 ae_nubus_attach(parent, self, aux)
113 struct device *parent, *self;
114 void *aux;
115 {
116 struct ae_softc *sc = (struct ae_softc *) self;
117 struct nubus_attach_args *na = (struct nubus_attach_args *) aux;
118 struct ifnet *ifp = &sc->sc_ec.ec_if;
119 bus_space_tag_t bst;
120 bus_space_handle_t bsh;
121 int success;
122 #ifdef AE_OLD_GET_ENADDR
123 int i;
124 #endif
125 u_int8_t myaddr[ETHER_ADDR_LEN];
126
127 bst = na->na_tag;
128 if (bus_space_map(bst, NUBUS_SLOT2PA(na->slot), NBMEMSIZE,
129 0, &bsh)) {
130 printf(": can't map memory space\n");
131 return;
132 }
133
134 sc->sc_regt = sc->sc_buft = bst;
135 sc->sc_flags = self->dv_cfdata->cf_flags;
136 sc->regs_rev = 0;
137 sc->use16bit = 1;
138 sc->vendor = ae_nb_card_vendor(na);
139 strncpy(sc->type_str, nubus_get_card_name(na->fmt),
140 INTERFACE_NAME_LEN);
141 sc->type_str[INTERFACE_NAME_LEN-1] = '\0';
142 sc->mem_size = 0;
143
144 success = 0;
145
146 switch (sc->vendor) {
147 case AE_VENDOR_APPLE: /* Apple-compatible cards */
148 case AE_VENDOR_ASANTE:
149 sc->regs_rev = 1;
150 if (bus_space_subregion(bst, bsh,
151 AE_REG_OFFSET, AE_REG_SIZE, &sc->sc_regh)) {
152 printf(": failed to map register space\n");
153 break;
154 }
155 if ((sc->mem_size = ae_size_card_memory(bst, bsh,
156 AE_DATA_OFFSET)) == 0) {
157 printf(": failed to determine size of RAM.\n");
158 break;
159 }
160 if (bus_space_subregion(bst, bsh,
161 AE_DATA_OFFSET, sc->mem_size, &sc->sc_bufh)) {
162 printf(": failed to map register space\n");
163 break;
164 }
165 #ifdef AE_OLD_GET_ENADDR
166 /* Get station address from on-board ROM */
167 for (i = 0; i < ETHER_ADDR_LEN; ++i)
168 myaddr[i] =
169 bus_space_read_1(bst, bsh, (AE_ROM_OFFSET + i * 2));
170 #else
171 if (ae_nb_get_enaddr(na, myaddr)) {
172 printf(": can't find MAC address\n");
173 break;
174 }
175 #endif
176
177 success = 1;
178 break;
179
180 case AE_VENDOR_DAYNA:
181 if (bus_space_subregion(bst, bsh,
182 DP_REG_OFFSET, AE_REG_SIZE, &sc->sc_regh)) {
183 printf(": failed to map register space\n");
184 break;
185 }
186 sc->mem_size = 8192;
187 if (bus_space_subregion(bst, bsh,
188 DP_DATA_OFFSET, sc->mem_size, &sc->sc_bufh)) {
189 printf(": failed to map register space\n");
190 break;
191 }
192 #ifdef AE_OLD_GET_ENADDR
193 /* Get station address from on-board ROM */
194 for (i = 0; i < ETHER_ADDR_LEN; ++i)
195 myaddr[i] =
196 bus_space_read_1(bst, bsh, (DP_ROM_OFFSET + i * 2));
197 #else
198 if (ae_nb_get_enaddr(na, myaddr)) {
199 printf(": can't find MAC address\n");
200 break;
201 }
202 #endif
203
204 printf(": unsupported Dayna hardware\n");
205 break;
206
207 case AE_VENDOR_FARALLON:
208 sc->regs_rev = 1;
209 if (bus_space_subregion(bst, bsh,
210 AE_REG_OFFSET, AE_REG_SIZE, &sc->sc_regh)) {
211 printf(": failed to map register space\n");
212 break;
213 }
214 if ((sc->mem_size = ae_size_card_memory(bst, bsh,
215 AE_DATA_OFFSET)) == 0) {
216 printf(": failed to determine size of RAM.\n");
217 break;
218 }
219 if (bus_space_subregion(bst, bsh,
220 AE_DATA_OFFSET, sc->mem_size, &sc->sc_bufh)) {
221 printf(": failed to map register space\n");
222 break;
223 }
224 #ifdef AE_OLD_GET_ENADDR
225 /* Get station address from on-board ROM */
226 for (i = 0; i < ETHER_ADDR_LEN; ++i)
227 myaddr[i] =
228 bus_space_read_1(bst, bsh, (FE_ROM_OFFSET + i));
229 #else
230 if (ae_nb_get_enaddr(na, myaddr)) {
231 printf(": can't find MAC address\n");
232 break;
233 }
234 #endif
235
236 success = 1;
237 break;
238
239 case AE_VENDOR_FOCUS:
240 printf(": unsupported Focus hardware\n");
241 break;
242
243 case AE_VENDOR_INTERLAN:
244 if (bus_space_subregion(bst, bsh,
245 GC_REG_OFFSET, AE_REG_SIZE, &sc->sc_regh)) {
246 printf(": failed to map register space\n");
247 break;
248 }
249 if ((sc->mem_size = ae_size_card_memory(bst, bsh,
250 GC_DATA_OFFSET)) == 0) {
251 printf(": failed to determine size of RAM.\n");
252 break;
253 }
254 if (bus_space_subregion(bst, bsh,
255 GC_DATA_OFFSET, sc->mem_size, &sc->sc_bufh)) {
256 printf(": failed to map register space\n");
257 break;
258 }
259
260 /* reset the NIC chip */
261 bus_space_write_1(bst, bsh, GC_RESET_OFFSET, 0);
262
263 if (ae_nb_get_enaddr(na, sc->sc_arpcom.ac_enaddr)) {
264 /* Fall back to snarf directly from ROM. Ick. */
265 for (i = 0; i < ETHER_ADDR_LEN; ++i)
266 myaddr[i] =
267 bus_space_read_1(bst, bsh,
268 (GC_ROM_OFFSET + i * 4));
269 }
270
271 success = 1;
272 break;
273
274 case AE_VENDOR_KINETICS:
275 sc->use16bit = 0;
276 if (bus_space_subregion(bst, bsh,
277 KE_REG_OFFSET, AE_REG_SIZE, &sc->sc_regh)) {
278 printf(": failed to map register space\n");
279 break;
280 }
281 if ((sc->mem_size = ae_size_card_memory(bst, bsh,
282 KE_DATA_OFFSET)) == 0) {
283 printf(": failed to determine size of RAM.\n");
284 break;
285 }
286 if (bus_space_subregion(bst, bsh,
287 KE_DATA_OFFSET, sc->mem_size, &sc->sc_bufh)) {
288 printf(": failed to map register space\n");
289 break;
290 }
291 if (ae_nb_get_enaddr(na, myaddr)) {
292 printf(": can't find MAC address\n");
293 break;
294 }
295
296 success = 1;
297 break;
298
299 default:
300 break;
301 }
302
303 if (!success) {
304 bus_space_unmap(bst, bsh, NBMEMSIZE);
305 return;
306 }
307
308 ifp->if_watchdog = ae_nb_watchdog; /* Override watchdog */
309 if (aesetup(sc, myaddr)) {
310 bus_space_unmap(bst, bsh, NBMEMSIZE);
311 return;
312 }
313
314 /* make sure interrupts are vectored to us */
315 add_nubus_intr(na->slot, aeintr, sc);
316 }
317
318 static int
319 ae_nb_card_vendor(na)
320 struct nubus_attach_args *na;
321 {
322 int vendor;
323
324 switch (na->drsw) {
325 case NUBUS_DRSW_3COM:
326 case NUBUS_DRSW_APPLE:
327 case NUBUS_DRSW_TECHWORKS:
328 vendor = AE_VENDOR_APPLE;
329 break;
330 case NUBUS_DRSW_ASANTE:
331 vendor = AE_VENDOR_ASANTE;
332 break;
333 case NUBUS_DRSW_FARALLON:
334 vendor = AE_VENDOR_FARALLON;
335 break;
336 case NUBUS_DRSW_FOCUS:
337 vendor = AE_VENDOR_FOCUS;
338 break;
339 case NUBUS_DRSW_GATOR:
340 switch (na->drhw) {
341 default:
342 case NUBUS_DRHW_INTERLAN:
343 vendor = AE_VENDOR_INTERLAN;
344 break;
345 case NUBUS_DRHW_KINETICS:
346 if (strncmp(
347 nubus_get_card_name(na->fmt), "EtherPort", 9) == 0)
348 vendor = AE_VENDOR_KINETICS;
349 else
350 vendor = AE_VENDOR_DAYNA;
351 break;
352 }
353 break;
354 default:
355 #ifdef AE_DEBUG
356 printf("Unknown ethernet drsw: %x\n", na->drsw);
357 #endif
358 vendor = AE_VENDOR_UNKNOWN;
359 }
360 return vendor;
361 }
362
363 static int
364 ae_nb_get_enaddr(na, ep)
365 struct nubus_attach_args *na;
366 u_int8_t *ep;
367 {
368 nubus_dir dir;
369 nubus_dirent dirent;
370
371 /*
372 * XXX - note hardwired resource IDs here (0x80); these are
373 * assumed to be used by all cards, but should be fixed when
374 * we find out more about Ethernet card resources.
375 */
376 nubus_get_main_dir(na->fmt, &dir);
377 if (nubus_find_rsrc(na->fmt, &dir, 0x80, &dirent) <= 0)
378 return 1;
379 nubus_get_dir_from_rsrc(na->fmt, &dirent, &dir);
380 if (nubus_find_rsrc(na->fmt, &dir, 0x80, &dirent) <= 0)
381 return 1;
382 if (nubus_get_ind_data(na->fmt, &dirent, ep, ETHER_ADDR_LEN) <= 0)
383 return 1;
384
385 return 0;
386 }
387
388 static void
389 ae_nb_watchdog(ifp)
390 struct ifnet *ifp;
391 {
392 struct ae_softc *sc = ifp->if_softc;
393
394 #if 1
395 /*
396 * This is a kludge! The via code seems to miss slot interrupts
397 * sometimes. This kludges around that by calling the handler
398 * by hand if the watchdog is activated. -- XXX (akb)
399 */
400 (*via2itab[1])((void *) 1);
401 #endif
402
403 log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
404 ++ifp->if_oerrors;
405
406 aereset(sc);
407 }
408