if_ae_nubus.c revision 1.6 1 /* $NetBSD: if_ae_nubus.c,v 1.6 1997/03/10 17:55:15 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
44 #ifdef INET
45 #include <netinet/in.h>
46 #include <netinet/if_ether.h>
47 #endif
48
49 #include <machine/bus.h>
50 #include <machine/viareg.h>
51
52 #include "nubus.h"
53 #include <dev/ic/dp8390reg.h>
54 #include "if_aereg.h"
55 #include "if_aevar.h"
56
57 static int ae_nubus_match __P((struct device *, struct cfdata *, void *));
58 static void ae_nubus_attach __P((struct device *, struct device *, void *));
59 static int ae_nb_card_vendor __P((struct nubus_attach_args *));
60 static int ae_nb_get_enaddr __P((struct nubus_attach_args *, u_int8_t *));
61 static void ae_nb_watchdog __P((struct ifnet *));
62
63 struct cfattach ae_nubus_ca = {
64 sizeof(struct ae_softc), ae_nubus_match, ae_nubus_attach
65 };
66
67 static int
68 ae_nubus_match(parent, cf, aux)
69 struct device *parent;
70 struct cfdata *cf;
71 void *aux;
72 {
73 struct nubus_attach_args *na = (struct nubus_attach_args *) aux;
74 bus_space_handle_t bsh;
75 int rv;
76
77 if (bus_space_map(na->na_tag, NUBUS_SLOT2PA(na->slot), NBMEMSIZE,
78 0, &bsh))
79 return (0);
80
81 rv = 0;
82
83 if (na->category == NUBUS_CATEGORY_NETWORK &&
84 na->type == NUBUS_TYPE_ETHERNET) {
85 switch (ae_nb_card_vendor(na)) {
86 case AE_VENDOR_APPLE:
87 case AE_VENDOR_ASANTE:
88 case AE_VENDOR_FARALLON:
89 case AE_VENDOR_INTERLAN:
90 case AE_VENDOR_KINETICS:
91 rv = 1;
92 break;
93 case AE_VENDOR_DAYNA:
94 case AE_VENDOR_FOCUS:
95 rv = UNSUPP;
96 break;
97 default:
98 break;
99 }
100 }
101
102 bus_space_unmap(na->na_tag, bsh, NBMEMSIZE);
103
104 return rv;
105 }
106
107 /*
108 * Install interface into kernel networking data structures
109 */
110 static void
111 ae_nubus_attach(parent, self, aux)
112 struct device *parent, *self;
113 void *aux;
114 {
115 struct ae_softc *sc = (struct ae_softc *) self;
116 struct nubus_attach_args *na = (struct nubus_attach_args *) aux;
117 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
118 bus_space_tag_t bst;
119 bus_space_handle_t bsh;
120 int success;
121 #ifdef AE_OLD_GET_ENADDR
122 int i;
123 #endif
124
125 bst = na->na_tag;
126 if (bus_space_map(bst, NUBUS_SLOT2PA(na->slot), NBMEMSIZE,
127 0, &bsh)) {
128 printf(": can't map memory space\n");
129 return;
130 }
131
132 sc->sc_regt = sc->sc_buft = bst;
133 sc->sc_flags = self->dv_cfdata->cf_flags;
134 sc->regs_rev = 0;
135 sc->use16bit = 1;
136 sc->vendor = ae_nb_card_vendor(na);
137 strncpy(sc->type_str, nubus_get_card_name(na->fmt),
138 INTERFACE_NAME_LEN);
139 sc->type_str[INTERFACE_NAME_LEN-1] = '\0';
140 sc->mem_size = 0;
141
142 success = 0;
143
144 switch (sc->vendor) {
145 case AE_VENDOR_APPLE: /* Apple-compatible cards */
146 case AE_VENDOR_ASANTE:
147 sc->regs_rev = 1;
148 if (bus_space_subregion(bst, bsh,
149 AE_REG_OFFSET, AE_REG_SIZE, &sc->sc_regh)) {
150 printf(": failed to map register space\n");
151 break;
152 }
153 if ((sc->mem_size = ae_size_card_memory(bst, bsh,
154 AE_DATA_OFFSET)) == 0) {
155 printf(": failed to determine size of RAM.\n");
156 break;
157 }
158 if (bus_space_subregion(bst, bsh,
159 AE_DATA_OFFSET, sc->mem_size, &sc->sc_bufh)) {
160 printf(": failed to map register space\n");
161 break;
162 }
163 #ifdef AE_OLD_GET_ENADDR
164 /* Get station address from on-board ROM */
165 for (i = 0; i < ETHER_ADDR_LEN; ++i)
166 sc->sc_arpcom.ac_enaddr[i] =
167 bus_space_read_1(bst, bsh, (AE_ROM_OFFSET + i * 2));
168 #else
169 if (ae_nb_get_enaddr(na, sc->sc_arpcom.ac_enaddr)) {
170 printf(": can't find MAC address\n");
171 break;
172 }
173 #endif
174
175 success = 1;
176 break;
177
178 case AE_VENDOR_DAYNA:
179 if (bus_space_subregion(bst, bsh,
180 DP_REG_OFFSET, AE_REG_SIZE, &sc->sc_regh)) {
181 printf(": failed to map register space\n");
182 break;
183 }
184 sc->mem_size = 8192;
185 if (bus_space_subregion(bst, bsh,
186 DP_DATA_OFFSET, sc->mem_size, &sc->sc_bufh)) {
187 printf(": failed to map register space\n");
188 break;
189 }
190 #ifdef AE_OLD_GET_ENADDR
191 /* Get station address from on-board ROM */
192 for (i = 0; i < ETHER_ADDR_LEN; ++i)
193 sc->sc_arpcom.ac_enaddr[i] =
194 bus_space_read_1(bst, bsh, (DP_ROM_OFFSET + i * 2));
195 #else
196 if (ae_nb_get_enaddr(na, sc->sc_arpcom.ac_enaddr)) {
197 printf(": can't find MAC address\n");
198 break;
199 }
200 #endif
201
202 printf(": unsupported Dayna hardware\n");
203 break;
204
205 case AE_VENDOR_FARALLON:
206 sc->regs_rev = 1;
207 if (bus_space_subregion(bst, bsh,
208 AE_REG_OFFSET, AE_REG_SIZE, &sc->sc_regh)) {
209 printf(": failed to map register space\n");
210 break;
211 }
212 if ((sc->mem_size = ae_size_card_memory(bst, bsh,
213 AE_DATA_OFFSET)) == 0) {
214 printf(": failed to determine size of RAM.\n");
215 break;
216 }
217 if (bus_space_subregion(bst, bsh,
218 AE_DATA_OFFSET, sc->mem_size, &sc->sc_bufh)) {
219 printf(": failed to map register space\n");
220 break;
221 }
222 #ifdef AE_OLD_GET_ENADDR
223 /* Get station address from on-board ROM */
224 for (i = 0; i < ETHER_ADDR_LEN; ++i)
225 sc->sc_arpcom.ac_enaddr[i] =
226 bus_space_read_1(bst, bsh, (FE_ROM_OFFSET + i));
227 #else
228 if (ae_nb_get_enaddr(na, sc->sc_arpcom.ac_enaddr)) {
229 printf(": can't find MAC address\n");
230 break;
231 }
232 #endif
233
234 success = 1;
235 break;
236
237 case AE_VENDOR_FOCUS:
238 printf(": unsupported Focus hardware\n");
239 break;
240
241 case AE_VENDOR_INTERLAN:
242 if (bus_space_subregion(bst, bsh,
243 GC_REG_OFFSET, AE_REG_SIZE, &sc->sc_regh)) {
244 printf(": failed to map register space\n");
245 break;
246 }
247 if ((sc->mem_size = ae_size_card_memory(bst, bsh,
248 GC_DATA_OFFSET)) == 0) {
249 printf(": failed to determine size of RAM.\n");
250 break;
251 }
252 if (bus_space_subregion(bst, bsh,
253 GC_DATA_OFFSET, sc->mem_size, &sc->sc_bufh)) {
254 printf(": failed to map register space\n");
255 break;
256 }
257
258 /* reset the NIC chip */
259 bus_space_write_1(bst, bsh, GC_RESET_OFFSET, 0);
260
261 #ifdef AE_OLD_GET_ENADDR
262 /* Get station address from on-board ROM */
263 for (i = 0; i < ETHER_ADDR_LEN; ++i)
264 sc->sc_arpcom.ac_enaddr[i] =
265 bus_space_read_1(bst, bsh, (GC_ROM_OFFSET + i * 4));
266 #else
267 if (ae_nb_get_enaddr(na, sc->sc_arpcom.ac_enaddr)) {
268 printf(": can't find MAC address\n");
269 break;
270 }
271 #endif
272
273 success = 1;
274 break;
275
276 case AE_VENDOR_KINETICS:
277 sc->use16bit = 0;
278 if (bus_space_subregion(bst, bsh,
279 KE_REG_OFFSET, AE_REG_SIZE, &sc->sc_regh)) {
280 printf(": failed to map register space\n");
281 break;
282 }
283 if ((sc->mem_size = ae_size_card_memory(bst, bsh,
284 KE_DATA_OFFSET)) == 0) {
285 printf(": failed to determine size of RAM.\n");
286 break;
287 }
288 if (bus_space_subregion(bst, bsh,
289 KE_DATA_OFFSET, sc->mem_size, &sc->sc_bufh)) {
290 printf(": failed to map register space\n");
291 break;
292 }
293 if (ae_nb_get_enaddr(na, sc->sc_arpcom.ac_enaddr)) {
294 printf(": can't find MAC address\n");
295 break;
296 }
297
298 success = 1;
299 break;
300
301 default:
302 break;
303 }
304
305 if (!success) {
306 bus_space_unmap(bst, bsh, NBMEMSIZE);
307 return;
308 }
309
310 ifp->if_watchdog = ae_nb_watchdog; /* Override watchdog */
311 if (aesetup(sc)) {
312 bus_space_unmap(bst, bsh, NBMEMSIZE);
313 return;
314 }
315
316 /* make sure interrupts are vectored to us */
317 add_nubus_intr(na->slot, aeintr, sc);
318
319 #ifdef MAC68K_BROKEN_VIDEO
320 /*
321 * XXX -- enable nubus interrupts here. Should be done elsewhere,
322 * but that currently breaks with some nubus video cards'
323 * interrupts. So we only enable nubus interrupts if we
324 * have an ethernet card... i.e., we do it here.
325 */
326 enable_nubus_intr();
327 #endif
328 }
329
330 static int
331 ae_nb_card_vendor(na)
332 struct nubus_attach_args *na;
333 {
334 int vendor;
335
336 switch (na->drsw) {
337 case NUBUS_DRSW_3COM:
338 case NUBUS_DRSW_APPLE:
339 case NUBUS_DRSW_TECHWORKS:
340 vendor = AE_VENDOR_APPLE;
341 break;
342 case NUBUS_DRSW_ASANTE:
343 vendor = AE_VENDOR_ASANTE;
344 break;
345 case NUBUS_DRSW_FARALLON:
346 vendor = AE_VENDOR_FARALLON;
347 break;
348 case NUBUS_DRSW_FOCUS:
349 vendor = AE_VENDOR_FOCUS;
350 break;
351 case NUBUS_DRSW_GATOR:
352 switch (na->drhw) {
353 default:
354 case NUBUS_DRHW_INTERLAN:
355 vendor = AE_VENDOR_INTERLAN;
356 break;
357 case NUBUS_DRHW_KINETICS:
358 if (strncmp(
359 nubus_get_card_name(na->fmt), "EtherPort", 9) == 0)
360 vendor = AE_VENDOR_KINETICS;
361 else
362 vendor = AE_VENDOR_DAYNA;
363 break;
364 }
365 break;
366 default:
367 #ifdef AE_DEBUG
368 printf("Unknown ethernet drsw: %x\n", na->drsw);
369 #endif
370 vendor = AE_VENDOR_UNKNOWN;
371 }
372 return vendor;
373 }
374
375 static int
376 ae_nb_get_enaddr(na, ep)
377 struct nubus_attach_args *na;
378 u_int8_t *ep;
379 {
380 nubus_dir dir;
381 nubus_dirent dirent;
382
383 /*
384 * XXX - note hardwired resource IDs here (0x80); these are
385 * assumed to be used by all cards, but should be fixed when
386 * we find out more about Ethernet card resources.
387 */
388 nubus_get_main_dir(na->fmt, &dir);
389 if (nubus_find_rsrc(na->fmt, &dir, 0x80, &dirent) <= 0)
390 return 1;
391 nubus_get_dir_from_rsrc(na->fmt, &dirent, &dir);
392 if (nubus_find_rsrc(na->fmt, &dir, 0x80, &dirent) <= 0)
393 return 1;
394 if (nubus_get_ind_data(na->fmt, &dirent, ep, ETHER_ADDR_LEN) <= 0)
395 return 1;
396
397 return 0;
398 }
399
400 static void
401 ae_nb_watchdog(ifp)
402 struct ifnet *ifp;
403 {
404 struct ae_softc *sc = ifp->if_softc;
405
406 #if 1
407 /*
408 * This is a kludge! The via code seems to miss slot interrupts
409 * sometimes. This kludges around that by calling the handler
410 * by hand if the watchdog is activated. -- XXX (akb)
411 */
412 (*via2itab[1])((void *) 1);
413 #endif
414
415 log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
416 ++sc->sc_arpcom.ac_if.if_oerrors;
417
418 aereset(sc);
419 }
420