if_ae_nubus.c revision 1.7 1 /* $NetBSD: if_ae_nubus.c,v 1.7 1997/03/15 18:09:59 is 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 #ifdef AE_OLD_GET_ENADDR
264 /* Get station address from on-board ROM */
265 for (i = 0; i < ETHER_ADDR_LEN; ++i)
266 myaddr[i] =
267 bus_space_read_1(bst, bsh, (GC_ROM_OFFSET + i * 4));
268 #else
269 if (ae_nb_get_enaddr(na, myaddr)) {
270 printf(": can't find MAC address\n");
271 break;
272 }
273 #endif
274
275 success = 1;
276 break;
277
278 case AE_VENDOR_KINETICS:
279 sc->use16bit = 0;
280 if (bus_space_subregion(bst, bsh,
281 KE_REG_OFFSET, AE_REG_SIZE, &sc->sc_regh)) {
282 printf(": failed to map register space\n");
283 break;
284 }
285 if ((sc->mem_size = ae_size_card_memory(bst, bsh,
286 KE_DATA_OFFSET)) == 0) {
287 printf(": failed to determine size of RAM.\n");
288 break;
289 }
290 if (bus_space_subregion(bst, bsh,
291 KE_DATA_OFFSET, sc->mem_size, &sc->sc_bufh)) {
292 printf(": failed to map register space\n");
293 break;
294 }
295 if (ae_nb_get_enaddr(na, myaddr)) {
296 printf(": can't find MAC address\n");
297 break;
298 }
299
300 success = 1;
301 break;
302
303 default:
304 break;
305 }
306
307 if (!success) {
308 bus_space_unmap(bst, bsh, NBMEMSIZE);
309 return;
310 }
311
312 ifp->if_watchdog = ae_nb_watchdog; /* Override watchdog */
313 if (aesetup(sc, myaddr)) {
314 bus_space_unmap(bst, bsh, NBMEMSIZE);
315 return;
316 }
317
318 /* make sure interrupts are vectored to us */
319 add_nubus_intr(na->slot, aeintr, sc);
320
321 #ifdef MAC68K_BROKEN_VIDEO
322 /*
323 * XXX -- enable nubus interrupts here. Should be done elsewhere,
324 * but that currently breaks with some nubus video cards'
325 * interrupts. So we only enable nubus interrupts if we
326 * have an ethernet card... i.e., we do it here.
327 */
328 enable_nubus_intr();
329 #endif
330 }
331
332 static int
333 ae_nb_card_vendor(na)
334 struct nubus_attach_args *na;
335 {
336 int vendor;
337
338 switch (na->drsw) {
339 case NUBUS_DRSW_3COM:
340 case NUBUS_DRSW_APPLE:
341 case NUBUS_DRSW_TECHWORKS:
342 vendor = AE_VENDOR_APPLE;
343 break;
344 case NUBUS_DRSW_ASANTE:
345 vendor = AE_VENDOR_ASANTE;
346 break;
347 case NUBUS_DRSW_FARALLON:
348 vendor = AE_VENDOR_FARALLON;
349 break;
350 case NUBUS_DRSW_FOCUS:
351 vendor = AE_VENDOR_FOCUS;
352 break;
353 case NUBUS_DRSW_GATOR:
354 switch (na->drhw) {
355 default:
356 case NUBUS_DRHW_INTERLAN:
357 vendor = AE_VENDOR_INTERLAN;
358 break;
359 case NUBUS_DRHW_KINETICS:
360 if (strncmp(
361 nubus_get_card_name(na->fmt), "EtherPort", 9) == 0)
362 vendor = AE_VENDOR_KINETICS;
363 else
364 vendor = AE_VENDOR_DAYNA;
365 break;
366 }
367 break;
368 default:
369 #ifdef AE_DEBUG
370 printf("Unknown ethernet drsw: %x\n", na->drsw);
371 #endif
372 vendor = AE_VENDOR_UNKNOWN;
373 }
374 return vendor;
375 }
376
377 static int
378 ae_nb_get_enaddr(na, ep)
379 struct nubus_attach_args *na;
380 u_int8_t *ep;
381 {
382 nubus_dir dir;
383 nubus_dirent dirent;
384
385 /*
386 * XXX - note hardwired resource IDs here (0x80); these are
387 * assumed to be used by all cards, but should be fixed when
388 * we find out more about Ethernet card resources.
389 */
390 nubus_get_main_dir(na->fmt, &dir);
391 if (nubus_find_rsrc(na->fmt, &dir, 0x80, &dirent) <= 0)
392 return 1;
393 nubus_get_dir_from_rsrc(na->fmt, &dirent, &dir);
394 if (nubus_find_rsrc(na->fmt, &dir, 0x80, &dirent) <= 0)
395 return 1;
396 if (nubus_get_ind_data(na->fmt, &dirent, ep, ETHER_ADDR_LEN) <= 0)
397 return 1;
398
399 return 0;
400 }
401
402 static void
403 ae_nb_watchdog(ifp)
404 struct ifnet *ifp;
405 {
406 struct ae_softc *sc = ifp->if_softc;
407
408 #if 1
409 /*
410 * This is a kludge! The via code seems to miss slot interrupts
411 * sometimes. This kludges around that by calling the handler
412 * by hand if the watchdog is activated. -- XXX (akb)
413 */
414 (*via2itab[1])((void *) 1);
415 #endif
416
417 log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
418 ++ifp->if_oerrors;
419
420 aereset(sc);
421 }
422