1/*	$NetBSD: if_ae_nubus.c,v 1.40 2008/04/04 09:49:33 hauke 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. The name of the author may not be used to endorse or promote products
16 *    derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29/*
30 * Some parts are derived from code adapted for MacBSD by Brad Parker
31 * <brad@fcr.com>.
32 *
33 * Currently supports:
34 *	Apple NB Ethernet Card
35 *	Apple NB Ethernet Card II
36 *	Interlan A310 NuBus Ethernet card
37 *	Cayman Systems GatorCard
38 *	Asante MacCon II/E
39 *	Kinetics EtherPort SE/30
40 */
41
42#include <sys/cdefs.h>
43__KERNEL_RCSID(0, "$NetBSD: if_ae_nubus.c,v 1.40 2008/04/04 09:49:33 hauke Exp $");
44
45#include <sys/param.h>
46#include <sys/device.h>
47#include <sys/errno.h>
48#include <sys/ioctl.h>
49#include <sys/malloc.h>
50#include <sys/socket.h>
51#include <sys/syslog.h>
52#include <sys/systm.h>
53
54#include <net/if.h>
55#include <net/if_media.h>
56#include <net/if_ether.h>
57
58#include <machine/bus.h>
59#include <machine/viareg.h>
60
61#include <dev/ic/dp8390reg.h>
62#include <dev/ic/dp8390var.h>
63#include <mac68k/nubus/nubus.h>
64#include <mac68k/dev/if_aevar.h>
65#include <mac68k/dev/if_aereg.h>
66
67static int	ae_nubus_match(device_t, cfdata_t, void *);
68static void	ae_nubus_attach(device_t, device_t, void *);
69static int	ae_nb_card_vendor(bus_space_tag_t, bus_space_handle_t,
70		    struct nubus_attach_args *);
71static int	ae_nb_get_enaddr(bus_space_tag_t, bus_space_handle_t,
72		    struct nubus_attach_args *, u_int8_t *);
73#ifdef DEBUG
74static void	ae_nb_watchdog(struct ifnet *);
75#endif
76
77void		ae_nubus_intr(void *);
78
79CFATTACH_DECL_NEW(ae_nubus, sizeof(struct dp8390_softc),
80    ae_nubus_match, ae_nubus_attach, NULL, NULL);
81
82static int
83ae_nubus_match(device_t parent, cfdata_t cf, void *aux)
84{
85	struct nubus_attach_args *na = aux;
86	bus_space_handle_t bsh;
87	int rv;
88
89	if (bus_space_map(na->na_tag, NUBUS_SLOT2PA(na->slot), NBMEMSIZE,
90	    0, &bsh))
91		return (0);
92
93	rv = 0;
94
95	if (na->category == NUBUS_CATEGORY_NETWORK &&
96	    na->type == NUBUS_TYPE_ETHERNET) {
97		switch (ae_nb_card_vendor(na->na_tag, bsh, na)) {
98		case DP8390_VENDOR_APPLE:
99		case DP8390_VENDOR_ASANTE:
100		case DP8390_VENDOR_FARALLON:
101		case DP8390_VENDOR_INTERLAN:
102		case DP8390_VENDOR_KINETICS:
103		case DP8390_VENDOR_CABLETRON:
104			rv = 1;
105			break;
106		case DP8390_VENDOR_DAYNA:
107			rv = UNSUPP;
108			break;
109		default:
110			break;
111		}
112	}
113
114	bus_space_unmap(na->na_tag, bsh, NBMEMSIZE);
115
116	return rv;
117}
118
119/*
120 * Install interface into kernel networking data structures
121 */
122static void
123ae_nubus_attach(device_t parent, device_t self, void *aux)
124{
125	struct dp8390_softc *sc = device_private(self);
126	struct nubus_attach_args *na = aux;
127#ifdef DEBUG
128	struct ifnet *ifp = &sc->sc_ec.ec_if;
129#endif
130	bus_space_tag_t bst;
131	bus_space_handle_t bsh;
132	int i, success;
133	const char *cardtype;
134
135	sc->sc_dev = self;
136	bst = na->na_tag;
137	if (bus_space_map(bst, NUBUS_SLOT2PA(na->slot), NBMEMSIZE,
138	    0, &bsh)) {
139		aprint_error(": can't map memory space\n");
140		return;
141	}
142
143	sc->sc_regt = sc->sc_buft = bst;
144	sc->sc_flags = device_cfdata(self)->cf_flags;
145
146	cardtype = nubus_get_card_name(bst, bsh, na->fmt);
147
148	sc->is790 = 0;
149
150	sc->mem_start = 0;
151	sc->mem_size = 0;
152
153	success = 0;
154
155	switch (ae_nb_card_vendor(bst, bsh, na)) {
156	case DP8390_VENDOR_APPLE:	/* Apple-compatible cards */
157	case DP8390_VENDOR_ASANTE:
158		/* Map register offsets */
159		for (i = 0; i < 16; i++) /* reverse order, longword aligned */
160			sc->sc_reg_map[i] = (15 - i) << 2;
161
162		sc->dcr_reg = (ED_DCR_FT1 | ED_DCR_WTS | ED_DCR_LS);
163		if (bus_space_subregion(bst, bsh,
164		    AE_REG_OFFSET, AE_REG_SIZE, &sc->sc_regh)) {
165			aprint_error(": failed to map register space\n");
166			break;
167		}
168		if ((sc->mem_size = ae_size_card_memory(bst, bsh,
169		    AE_DATA_OFFSET)) == 0) {
170			aprint_error(": failed to determine size of RAM.\n");
171			break;
172		}
173		if (bus_space_subregion(bst, bsh,
174		    AE_DATA_OFFSET, sc->mem_size, &sc->sc_bufh)) {
175			aprint_error(": failed to map register space\n");
176			break;
177		}
178#ifdef AE_OLD_GET_ENADDR
179		/* Get station address from on-board ROM */
180		for (i = 0; i < ETHER_ADDR_LEN; ++i)
181			sc->sc_enaddr[i] =
182			    bus_space_read_1(bst, bsh, (AE_ROM_OFFSET + i * 2));
183#else
184		if (ae_nb_get_enaddr(bst, bsh, na, sc->sc_enaddr)) {
185			aprint_error(": can't find MAC address\n");
186			break;
187		}
188#endif
189
190		success = 1;
191		break;
192
193	case DP8390_VENDOR_DAYNA:
194		/* Map register offsets */
195		for (i = 0; i < 16; i++) /* normal order, longword aligned */
196			sc->sc_reg_map[i] = i << 2;
197
198		sc->dcr_reg = (ED_DCR_FT1 | ED_DCR_WTS | ED_DCR_LS);
199		if (bus_space_subregion(bst, bsh,
200		    DP_REG_OFFSET, AE_REG_SIZE, &sc->sc_regh)) {
201			aprint_error(": failed to map register space\n");
202			break;
203		}
204		sc->mem_size = 8192;
205		if (bus_space_subregion(bst, bsh,
206		    DP_DATA_OFFSET, sc->mem_size, &sc->sc_bufh)) {
207			aprint_error(": failed to map register space\n");
208			break;
209		}
210#ifdef AE_OLD_GET_ENADDR
211		/* Get station address from on-board ROM */
212		for (i = 0; i < ETHER_ADDR_LEN; ++i)
213			sc->sc_enaddr[i] =
214			    bus_space_read_1(bst, bsh, (DP_ROM_OFFSET + i * 2));
215#else
216		if (ae_nb_get_enaddr(bst, bsh, na, sc->sc_enaddr)) {
217			aprint_error(": can't find MAC address\n");
218			break;
219		}
220#endif
221
222		aprint_error(": unsupported Dayna hardware\n");
223		break;
224
225	case DP8390_VENDOR_FARALLON:
226		/* Map register offsets */
227		for (i = 0; i < 16; i++) /* reverse order, longword aligned */
228			sc->sc_reg_map[i] = (15 - i) << 2;
229
230		sc->dcr_reg = (ED_DCR_FT1 | ED_DCR_WTS | ED_DCR_LS);
231		if (bus_space_subregion(bst, bsh,
232		    AE_REG_OFFSET, AE_REG_SIZE, &sc->sc_regh)) {
233			aprint_error(": failed to map register space\n");
234			break;
235		}
236		if ((sc->mem_size = ae_size_card_memory(bst, bsh,
237		    AE_DATA_OFFSET)) == 0) {
238			aprint_error(": failed to determine size of RAM.\n");
239			break;
240		}
241		if (bus_space_subregion(bst, bsh,
242		    AE_DATA_OFFSET, sc->mem_size, &sc->sc_bufh)) {
243			aprint_error(": failed to map register space\n");
244			break;
245		}
246#ifdef AE_OLD_GET_ENADDR
247		/* Get station address from on-board ROM */
248		for (i = 0; i < ETHER_ADDR_LEN; ++i)
249			sc->sc_enaddr[i] =
250			    bus_space_read_1(bst, bsh, (FE_ROM_OFFSET + i));
251#else
252		if (ae_nb_get_enaddr(bst, bsh, na, sc->sc_enaddr)) {
253			aprint_error(": can't find MAC address\n");
254			break;
255		}
256#endif
257
258		success = 1;
259		break;
260
261	case DP8390_VENDOR_INTERLAN:
262		/* Map register offsets */
263		for (i = 0; i < 16; i++) /* normal order, longword aligned */
264			sc->sc_reg_map[i] = i << 2;
265
266		sc->dcr_reg = (ED_DCR_FT1 | ED_DCR_WTS | ED_DCR_LS);
267		if (bus_space_subregion(bst, bsh,
268		    GC_REG_OFFSET, AE_REG_SIZE, &sc->sc_regh)) {
269			aprint_error(": failed to map register space\n");
270			break;
271		}
272		if ((sc->mem_size = ae_size_card_memory(bst, bsh,
273		    GC_DATA_OFFSET)) == 0) {
274			aprint_error(": failed to determine size of RAM.\n");
275			break;
276		}
277		if (bus_space_subregion(bst, bsh,
278		    GC_DATA_OFFSET, sc->mem_size, &sc->sc_bufh)) {
279			aprint_error(": failed to map register space\n");
280			break;
281		}
282
283		/* reset the NIC chip */
284		bus_space_write_1(bst, bsh, GC_RESET_OFFSET, 0);
285
286		if (ae_nb_get_enaddr(bst, bsh, na, sc->sc_enaddr)) {
287			/* Fall back to snarf directly from ROM.  Ick. */
288			for (i = 0; i < ETHER_ADDR_LEN; ++i)
289				sc->sc_enaddr[i] =
290				    bus_space_read_1(bst, bsh,
291				    (GC_ROM_OFFSET + i * 4));
292		}
293
294		success = 1;
295		break;
296
297	case DP8390_VENDOR_KINETICS:
298		/* Map register offsets */
299		for (i = 0; i < 16; i++) /* normal order, longword aligned */
300			sc->sc_reg_map[i] = i << 2;
301
302		if (bus_space_subregion(bst, bsh,
303		    KE_REG_OFFSET, AE_REG_SIZE, &sc->sc_regh)) {
304			aprint_error(": failed to map register space\n");
305			break;
306		}
307		if ((sc->mem_size = ae_size_card_memory(bst, bsh,
308		    KE_DATA_OFFSET)) == 0) {
309			aprint_error(": failed to determine size of RAM.\n");
310			break;
311		}
312		if (bus_space_subregion(bst, bsh,
313		    KE_DATA_OFFSET, sc->mem_size, &sc->sc_bufh)) {
314			aprint_error(": failed to map register space\n");
315			break;
316		}
317		if (ae_nb_get_enaddr(bst, bsh, na, sc->sc_enaddr)) {
318			aprint_error(": can't find MAC address\n");
319			break;
320		}
321
322		success = 1;
323		break;
324
325	case DP8390_VENDOR_CABLETRON:
326		/* Map register offsets */
327		for (i = 0; i < 16; i++)
328  			sc->sc_reg_map[i] =  i << 1 ;  /* normal order, word aligned */
329  		sc->dcr_reg = (ED_DCR_FT1 | ED_DCR_WTS | ED_DCR_LS);
330		if (bus_space_subregion(bst, bsh,
331		    CT_REG_OFFSET, AE_REG_SIZE, &sc->sc_regh)) {
332			aprint_error(": failed to map register space\n");
333			break;
334		}
335		if ((sc->mem_size = ae_size_card_memory(bst, bsh,
336		    CT_DATA_OFFSET)) == 0) {
337			aprint_error(": failed to determine size of RAM.\n");
338			break;
339		}
340		if (bus_space_subregion(bst, bsh,
341		    CT_DATA_OFFSET, sc->mem_size, &sc->sc_bufh)) {
342			aprint_error(": failed to map register space\n");
343			break;
344		}
345		if (ae_nb_get_enaddr(bst, bsh, na, sc->sc_enaddr)) {
346			aprint_error(": can't find MAC address\n");
347			break;
348		}
349		success = 1;
350		break;
351	default:
352		break;
353	}
354
355	if (!success) {
356		bus_space_unmap(bst, bsh, NBMEMSIZE);
357		return;
358	}
359
360	/*
361	 * Override test_mem and write_mbuf functions; other defaults
362	 * already work properly.
363	 */
364	sc->test_mem = ae_test_mem;
365	sc->write_mbuf = ae_write_mbuf;
366#ifdef DEBUG
367	ifp->if_watchdog = ae_nb_watchdog;	/* Override watchdog */
368#endif
369	sc->sc_media_init = dp8390_media_init;
370
371	/* Interface is always enabled. */
372	sc->sc_enabled = 1;
373
374	aprint_normal(": %s, %dKB memory\n", cardtype, sc->mem_size / 1024);
375
376	if (dp8390_config(sc)) {
377		bus_space_unmap(bst, bsh, NBMEMSIZE);
378		return;
379	}
380
381	/* make sure interrupts are vectored to us */
382	add_nubus_intr(na->slot, ae_nubus_intr, sc);
383}
384
385void
386ae_nubus_intr(void *arg)
387{
388	struct dp8390_softc *sc = arg;
389
390	(void)dp8390_intr(sc);
391}
392
393static int
394ae_nb_card_vendor(bus_space_tag_t bst, bus_space_handle_t bsh,
395    struct nubus_attach_args *na)
396{
397	int vendor;
398
399	switch (na->drsw) {
400	case NUBUS_DRSW_3COM:
401		switch (na->drhw) {
402		case NUBUS_DRHW_APPLE_SN:
403		case NUBUS_DRHW_APPLE_SNT:
404			vendor = DP8390_VENDOR_UNKNOWN;
405			break;
406		default:
407			vendor = DP8390_VENDOR_APPLE;
408			break;
409		}
410		break;
411	case NUBUS_DRSW_APPLE:
412		if (na->drhw == NUBUS_DRHW_ASANTE_LC) {
413			vendor = DP8390_VENDOR_UNKNOWN;
414			break;
415		}
416		/* FALLTHROUGH */
417	case NUBUS_DRSW_DAYNA2:
418	case NUBUS_DRSW_TECHWORKS:
419	case NUBUS_DRSW_TFLLAN:
420		if (na->drhw == NUBUS_DRHW_CABLETRON) {
421			vendor = DP8390_VENDOR_CABLETRON;
422		} else {
423			vendor = DP8390_VENDOR_APPLE;
424		}
425		break;
426	case NUBUS_DRSW_ASANTE:
427		vendor = DP8390_VENDOR_ASANTE;
428		break;
429	case NUBUS_DRSW_FARALLON:
430		vendor = DP8390_VENDOR_FARALLON;
431		break;
432	case NUBUS_DRSW_GATOR:
433		switch (na->drhw) {
434		default:
435		case NUBUS_DRHW_INTERLAN:
436			vendor = DP8390_VENDOR_INTERLAN;
437			break;
438		case NUBUS_DRHW_KINETICS:
439			if (strncmp(nubus_get_card_name(bst, bsh, na->fmt),
440			    "EtherPort", 9) == 0)
441				vendor = DP8390_VENDOR_KINETICS;
442			else
443				vendor = DP8390_VENDOR_DAYNA;
444			break;
445		}
446		break;
447	default:
448		vendor = DP8390_VENDOR_UNKNOWN;
449	}
450	return vendor;
451}
452
453static int
454ae_nb_get_enaddr(bus_space_tag_t bst, bus_space_handle_t bsh,
455    struct nubus_attach_args *na, u_int8_t *ep)
456{
457	nubus_dir dir;
458	nubus_dirent dirent;
459	int rv;
460
461	/*
462	 * XXX - note hardwired resource IDs here; these are assumed to
463	 * be used by all cards, but should be fixed when we find out
464	 * more about Ethernet card resources.
465	 */
466	nubus_get_main_dir(na->fmt, &dir);
467	switch (ae_nb_card_vendor(bst, bsh, na)) {
468	case DP8390_VENDOR_APPLE:
469		if (na->drsw == NUBUS_DRSW_TFLLAN) {	/* TFL LAN E410/E420 */
470			rv = nubus_find_rsrc(bst, bsh, na->fmt,
471			    &dir, 0x08, &dirent);
472			break;
473		}
474		/*FALLTHROUGH*/
475	default:
476		rv = nubus_find_rsrc(bst, bsh, na->fmt, &dir, 0x80, &dirent);
477		break;
478	}
479	if (rv <= 0)
480		return 1;
481	nubus_get_dir_from_rsrc(na->fmt, &dirent, &dir);
482	if (nubus_find_rsrc(bst, bsh, na->fmt, &dir, 0x80, &dirent) <= 0)
483		return 1;
484	if (nubus_get_ind_data(bst, bsh,
485	    na->fmt, &dirent, ep, ETHER_ADDR_LEN) <= 0)
486		return 1;
487
488	return 0;
489}
490
491#ifdef DEBUG
492static void
493ae_nb_watchdog(struct ifnet *ifp)
494{
495	struct dp8390_softc *sc = ifp->if_softc;
496
497/*
498 * This is a kludge!  The via code seems to miss slot interrupts
499 * sometimes.  This kludges around that by calling the handler
500 * by hand if the watchdog is activated. -- XXX (akb)
501 */
502	(*via2itab[1])((void *)1);
503
504	log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev));
505	++ifp->if_oerrors;
506
507	dp8390_reset(sc);
508}
509#endif
510