xref: /openbsd/sys/dev/isa/if_ep_isa.c (revision 09467b48)
1 /*	$OpenBSD: if_ep_isa.c,v 1.31 2015/11/25 11:20:38 mpi Exp $	*/
2 /*	$NetBSD: if_ep_isa.c,v 1.5 1996/05/12 23:52:36 mycroft Exp $	*/
3 
4 /*
5  * Copyright (c) 1996 Jason R. Thorpe <thorpej@beer.org>
6  * Copyright (c) 1994 Herb Peyerl <hpeyerl@beer.org>
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by Herb Peyerl.
20  * 4. The name of Herb Peyerl may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Note: Most of the code here was written by Theo de Raadt originally,
35  * ie. all the mechanics of probing for all cards on first call and then
36  * searching for matching devices on subsequent calls.
37  */
38 
39 #include "bpfilter.h"
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/mbuf.h>
44 #include <sys/socket.h>
45 #include <sys/ioctl.h>
46 #include <sys/errno.h>
47 #include <sys/syslog.h>
48 #include <sys/selinfo.h>
49 #include <sys/timeout.h>
50 #include <sys/device.h>
51 #include <sys/queue.h>
52 
53 #include <net/if.h>
54 #include <net/if_media.h>
55 
56 #include <netinet/in.h>
57 #include <netinet/if_ether.h>
58 
59 #if NBPFILTER > 0
60 #include <net/bpf.h>
61 #endif
62 
63 #include <machine/cpu.h>
64 #include <machine/bus.h>
65 #include <machine/intr.h>
66 
67 #include <dev/mii/mii.h>
68 #include <dev/mii/miivar.h>
69 
70 #include <dev/ic/elink3var.h>
71 #include <dev/ic/elink3reg.h>
72 
73 #include <dev/isa/isavar.h>
74 #include <dev/isa/elink.h>
75 
76 int ep_isa_probe(struct device *, void *, void *);
77 void ep_isa_attach(struct device *, struct device *, void *);
78 
79 struct cfattach ep_isa_ca = {
80 	sizeof(struct ep_softc), ep_isa_probe, ep_isa_attach
81 };
82 
83 static	void epaddcard(int, int, int, u_short);
84 
85 /*
86  * This keeps track of which ISAs have been through an ep probe sequence.
87  * A simple static variable isn't enough, since it's conceivable that
88  * a system might have more than one ISA bus.
89  *
90  * The "er_bus" member is the unit number of the parent ISA bus, e.g. "0"
91  * for "isa0".
92  */
93 struct ep_isa_done_probe {
94 	LIST_ENTRY(ep_isa_done_probe)	er_link;
95 	int				er_bus;
96 };
97 static LIST_HEAD(, ep_isa_done_probe) ep_isa_all_probes;
98 static int ep_isa_probes_initialized;
99 
100 #define MAXEPCARDS	20	/* if you have more than 20, you lose */
101 
102 static struct epcard {
103 	int	bus;
104 	int	iobase;
105 	int	irq;
106 	char	available;
107 	u_short	model;
108 } epcards[MAXEPCARDS];
109 static int nepcards;
110 
111 static void
112 epaddcard(int bus, int iobase, int irq, u_short model)
113 {
114 	if (nepcards >= MAXEPCARDS)
115 		return;
116 	epcards[nepcards].bus = bus;
117 	epcards[nepcards].iobase = iobase;
118 	epcards[nepcards].irq = (irq == 2) ? 9 : irq;
119 	epcards[nepcards].available = 1;
120 	epcards[nepcards].model = model;
121 	nepcards++;
122 }
123 
124 /*
125  * 3c509 cards on the ISA bus are probed in ethernet address order.
126  * The probe sequence requires careful orchestration, and we'd like
127  * to allow the irq and base address to be wildcarded. So, we
128  * probe all the cards the first time epprobe() is called. On subsequent
129  * calls we look for matching cards.
130  */
131 int
132 ep_isa_probe(struct device *parent, void *match, void *aux)
133 {
134 	struct isa_attach_args *ia = aux;
135 	bus_space_tag_t iot = ia->ia_iot;
136 	bus_space_handle_t ioh;
137 	int slot, iobase, irq, i, pnp;
138 	u_int16_t vendor, model;
139 	struct ep_isa_done_probe *er;
140 	int bus = parent->dv_unit;
141 
142 	if (ep_isa_probes_initialized == 0) {
143 		LIST_INIT(&ep_isa_all_probes);
144 		ep_isa_probes_initialized = 1;
145 	}
146 
147 	/*
148 	 * Probe this bus if we haven't done so already.
149 	 */
150 	LIST_FOREACH(er, &ep_isa_all_probes, er_link)
151 		if (er->er_bus == parent->dv_unit)
152 			goto bus_probed;
153 
154 	/*
155 	 * Mark this bus so we don't probe it again.
156 	 */
157 	er = (struct ep_isa_done_probe *)
158 	    malloc(sizeof(struct ep_isa_done_probe), M_DEVBUF, M_NOWAIT);
159 	if (er == NULL)
160 		panic("ep_isa_probe: can't allocate state storage");
161 
162 	er->er_bus = bus;
163 	LIST_INSERT_HEAD(&ep_isa_all_probes, er, er_link);
164 
165 	/*
166 	 * Map the Etherlink ID port for the probe sequence.
167 	 */
168 	if (bus_space_map(iot, ELINK_ID_PORT, 1, 0, &ioh)) {
169 		printf("ep_isa_probe: can't map Etherlink ID port\n");
170 		return 0;
171 	}
172 
173 	for (slot = 0; slot < MAXEPCARDS; slot++) {
174 		elink_reset(iot, ioh, parent->dv_unit);
175 		elink_idseq(iot, ioh, ELINK_509_POLY);
176 
177 		/* Untag all the adapters so they will talk to us. */
178 		if (slot == 0)
179 			bus_space_write_1(iot, ioh, 0, TAG_ADAPTER + 0);
180 
181 		vendor = htons(epreadeeprom(iot, ioh, EEPROM_MFG_ID));
182 		if (vendor != MFG_ID)
183 			continue;
184 
185 		model = htons(epreadeeprom(iot, ioh, EEPROM_PROD_ID));
186 		if ((model & 0xfff0) != PROD_ID_3C509) {
187 #ifndef trusted
188 			printf("ep_isa_probe: ignoring model %04x\n",
189 			    model);
190 #endif
191 			continue;
192 		}
193 
194 		iobase = epreadeeprom(iot, ioh, EEPROM_ADDR_CFG);
195 		iobase = (iobase & 0x1f) * 0x10 + 0x200;
196 
197 		irq = epreadeeprom(iot, ioh, EEPROM_RESOURCE_CFG);
198 		irq >>= 12;
199 
200 		pnp = epreadeeprom(iot, ioh, EEPROM_PNP) & 8;
201 
202 		/* so card will not respond to contention again */
203 		bus_space_write_1(iot, ioh, 0, TAG_ADAPTER + 1);
204 
205 		if ((model & 0xfff0) == PROD_ID_3C509 && pnp != 0)
206 			continue;
207 
208 		/*
209 		 * XXX: this should probably not be done here
210 		 * because it enables the drq/irq lines from
211 		 * the board. Perhaps it should be done after
212 		 * we have checked for irq/drq collisions?
213 		 */
214 		bus_space_write_1(iot, ioh, 0, ACTIVATE_ADAPTER_TO_CONFIG);
215 		epaddcard(bus, iobase, irq, model);
216 	}
217 	/* XXX should we sort by ethernet address? */
218 
219 	bus_space_unmap(iot, ioh, 1);
220 
221  bus_probed:
222 
223 	for (i = 0; i < nepcards; i++) {
224 		if (epcards[i].bus != bus)
225 			continue;
226 		if (epcards[i].available == 0)
227 			continue;
228 		if (ia->ia_iobase != IOBASEUNK &&
229 		    ia->ia_iobase != epcards[i].iobase)
230 			continue;
231 		if (ia->ia_irq != IRQUNK &&
232 		    ia->ia_irq != epcards[i].irq)
233 			continue;
234 		goto good;
235 	}
236 	return 0;
237 
238 good:
239 	epcards[i].available = 0;
240 	ia->ia_iobase = epcards[i].iobase;
241 	ia->ia_irq = epcards[i].irq;
242 	ia->ia_iosize = 0x10;
243 	ia->ia_msize = 0;
244 	ia->ia_aux = (void *)(long)(epcards[i].model);
245 	return 1;
246 }
247 
248 void
249 ep_isa_attach(struct device *parent, struct device *self, void *aux)
250 {
251 	struct ep_softc *sc = (void *)self;
252 	struct isa_attach_args *ia = aux;
253 	bus_space_tag_t iot = ia->ia_iot;
254 	bus_space_handle_t ioh;
255 	int chipset;
256 
257 	/* Map i/o space. */
258 	if (bus_space_map(iot, ia->ia_iobase, ia->ia_iosize, 0, &ioh))
259 		panic("ep_isa_attach: can't map i/o space");
260 
261 	sc->sc_iot = iot;
262 	sc->sc_ioh = ioh;
263 	sc->bustype = EP_BUS_ISA;
264 
265 	printf(":");
266 
267 	chipset = (int)(long)ia->ia_aux;
268 	if ((chipset & 0xfff0) == PROD_ID_3C509) {
269 		epconfig(sc, EP_CHIPSET_3C509, NULL);
270 	} else {
271 		/*
272 		 * XXX: Maybe a 3c515, but the check in ep_isa_probe looks
273 		 * at the moment only for a 3c509.
274 		 */
275 		epconfig(sc, EP_CHIPSET_UNKNOWN, NULL);
276 	}
277 
278 	sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
279 	    IPL_NET, epintr, sc, sc->sc_dev.dv_xname);
280 }
281