eisaconf.c revision 139749
1/*-
2 * EISA bus probe and attach routines
3 *
4 * Copyright (c) 1995, 1996 Justin T. Gibbs.
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 immediately at the beginning of the file, without modification,
12 *    this list of conditions, and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: head/sys/dev/eisa/eisaconf.c 139749 2005-01-06 01:43:34Z imp $");
35
36#include "opt_eisa.h"
37
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/queue.h>
41#include <sys/limits.h>
42#include <sys/malloc.h>
43#include <sys/kernel.h>
44#include <sys/module.h>
45#include <sys/bus.h>
46
47#include <machine/bus.h>
48#include <machine/resource.h>
49#include <sys/rman.h>
50
51#include <dev/eisa/eisaconf.h>
52
53typedef struct resvaddr {
54        u_long	addr;				/* start address */
55        u_long	size;				/* size of reserved area */
56	int	flags;
57	struct resource *res;			/* resource manager handle */
58	LIST_ENTRY(resvaddr) links;		/* List links */
59} resvaddr_t;
60
61LIST_HEAD(resvlist, resvaddr);
62
63struct irq_node {
64	int	irq_no;
65	int	irq_trigger;
66	void	*idesc;
67	TAILQ_ENTRY(irq_node) links;
68};
69
70TAILQ_HEAD(irqlist, irq_node);
71
72struct eisa_ioconf {
73	int		slot;
74	struct resvlist	ioaddrs;	/* list of reserved I/O ranges */
75	struct resvlist maddrs;		/* list of reserved memory ranges */
76	struct irqlist	irqs;		/* list of reserved irqs */
77};
78
79/* To be replaced by the "super device" generic device structure... */
80struct eisa_device {
81	eisa_id_t		id;
82	struct eisa_ioconf	ioconf;
83};
84
85
86#define MAX_COL		79
87#ifndef EISA_SLOTS
88#define EISA_SLOTS 10   /* PCI clashes with higher ones.. fix later */
89#endif
90int num_eisa_slots = EISA_SLOTS;
91TUNABLE_INT("hw.eisa_slots", &num_eisa_slots);
92
93static devclass_t eisa_devclass;
94
95static int eisa_probe_slot(int slot, eisa_id_t *eisa_id);
96static void eisa_reg_print (device_t, char *, char *, int *);
97static struct irq_node * eisa_find_irq(struct eisa_device *e_dev, int rid);
98static struct resvaddr * eisa_find_maddr(struct eisa_device *e_dev, int rid);
99static struct resvaddr * eisa_find_ioaddr(struct eisa_device *e_dev, int rid);
100
101static int
102mainboard_probe(device_t dev)
103{
104	char *idstring;
105	eisa_id_t id = eisa_get_id(dev);
106
107	if (eisa_get_slot(dev) != 0)
108		return (ENXIO);
109
110	idstring = (char *)malloc(8 + sizeof(" (System Board)") + 1,
111				  M_DEVBUF, M_NOWAIT);
112	if (idstring == NULL) {
113		panic("Eisa probe unable to malloc");
114	}
115	sprintf(idstring, "%c%c%c%03x%01x (System Board)",
116		EISA_MFCTR_CHAR0(id),
117		EISA_MFCTR_CHAR1(id),
118		EISA_MFCTR_CHAR2(id),
119		EISA_PRODUCT_ID(id),
120		EISA_REVISION_ID(id));
121	device_set_desc(dev, idstring);
122
123	return (0);
124}
125
126static int
127mainboard_attach(device_t dev)
128{
129	return (0);
130}
131
132static device_method_t mainboard_methods[] = {
133	/* Device interface */
134	DEVMETHOD(device_probe,		mainboard_probe),
135	DEVMETHOD(device_attach,	mainboard_attach),
136
137	{ 0, 0 }
138};
139
140static driver_t mainboard_driver = {
141	"mainboard",
142	mainboard_methods,
143	1,
144};
145
146static devclass_t mainboard_devclass;
147
148DRIVER_MODULE(mainboard, eisa, mainboard_driver, mainboard_devclass, 0, 0);
149
150/*
151** probe for EISA devices
152*/
153static int
154eisa_probe(device_t dev)
155{
156	int devices_found, slot;
157	struct eisa_device *e_dev;
158	device_t child;
159	eisa_id_t eisa_id;
160
161	device_set_desc(dev, "EISA bus");
162
163	devices_found = 0;
164	for (slot = 0; slot < num_eisa_slots; slot++) {
165		eisa_id = 0;
166		if (eisa_probe_slot(slot, &eisa_id)) {
167			/*
168			 * If there's no card in the first slot (the
169			 * mainboard), then the system doesn't have EISA.
170			 * We abort the probe early in this case since
171			 * continuing on causes a hang on some systems.
172			 * Interestingly enough, the inb has been seen to
173			 * cause the hang.  However, aborting here causes
174			 * the Adaptec 2842 probe to fail so that driver
175			 * needs to be fixed separately.
176			 */
177			if (slot == 0)
178				break;
179			continue;
180		}
181
182		devices_found++;
183
184		/* Prepare an eisa_device_node for this slot */
185		e_dev = (struct eisa_device *)malloc(sizeof(*e_dev),
186						     M_DEVBUF, M_NOWAIT|M_ZERO);
187		if (!e_dev) {
188			device_printf(dev, "cannot malloc eisa_device");
189			break; /* Try to attach what we have already */
190		}
191
192		e_dev->id = eisa_id;
193		e_dev->ioconf.slot = slot;
194
195		/* Initialize our lists of reserved addresses */
196		LIST_INIT(&(e_dev->ioconf.ioaddrs));
197		LIST_INIT(&(e_dev->ioconf.maddrs));
198		TAILQ_INIT(&(e_dev->ioconf.irqs));
199
200		child = device_add_child(dev, NULL, -1);
201		device_set_ivars(child, e_dev);
202	}
203
204	/*
205	 * EISA busses themselves are not easily detectable, the easiest way
206	 * to tell if there is an eisa bus is if we found something - there
207	 * should be a motherboard "card" there somewhere.
208	 */
209	return devices_found ? 0 : ENXIO;
210}
211
212static int
213eisa_probe_slot(int slot, eisa_id_t *eisa_id)
214{
215	eisa_id_t probe_id;
216	int base, i, id_size;
217
218	probe_id = 0;
219	id_size = sizeof(probe_id);
220	base = 0x0c80 + (slot * 0x1000);
221
222	for (i = 0; i < id_size; i++)
223		probe_id |= inb(base + i) << ((id_size - i - 1) * CHAR_BIT);
224
225	/* If we found a card, return its EISA id. */
226	if ((probe_id & 0x80000000) == 0) {
227		*eisa_id = probe_id;
228		return (0);
229	}
230
231	return (ENXIO);
232}
233
234static void
235eisa_probe_nomatch(device_t dev, device_t child)
236{
237	u_int32_t	eisa_id = eisa_get_id(child);
238	u_int8_t	slot = eisa_get_slot(child);
239
240	device_printf(dev, "unknown card %c%c%c%03x%01x (0x%08x) at slot %d\n",
241		EISA_MFCTR_CHAR0(eisa_id),
242		EISA_MFCTR_CHAR1(eisa_id),
243		EISA_MFCTR_CHAR2(eisa_id),
244		EISA_PRODUCT_ID(eisa_id),
245		EISA_REVISION_ID(eisa_id),
246		eisa_id,
247		slot);
248
249	return;
250}
251
252static void
253eisa_reg_print (dev, string, separator, column)
254	device_t	dev;
255	char *		string;
256	char *		separator;
257	int *		column;
258{
259	int length = strlen(string);
260
261	length += (separator ? 2 : 1);
262
263	if (((*column) + length) >= MAX_COL) {
264		printf("\n");
265		(*column) = 0;
266	} else if ((*column) != 0) {
267		if (separator) {
268			printf("%c", *separator);
269			(*column)++;
270		}
271		printf(" ");
272		(*column)++;
273	}
274
275	if ((*column) == 0) {
276		(*column) += device_printf(dev, "%s", string);
277	} else {
278		(*column) += printf("%s", string);
279	}
280
281	return;
282}
283
284static int
285eisa_print_child(device_t dev, device_t child)
286{
287	char			buf[81];
288	struct eisa_device *	e_dev = device_get_ivars(child);
289	int			rid;
290	struct irq_node *	irq;
291	struct resvaddr *	resv;
292	char			separator = ',';
293	int			column = 0;
294	int			retval = 0;
295
296	if (device_get_desc(child)) {
297		snprintf(buf, sizeof(buf), "<%s>", device_get_desc(child));
298		eisa_reg_print(child, buf, NULL, &column);
299	}
300
301	rid = 0;
302	while ((resv = eisa_find_ioaddr(e_dev, rid++))) {
303		if ((resv->size == 1) ||
304		    (resv->flags & RESVADDR_BITMASK)) {
305			snprintf(buf, sizeof(buf), "%s%lx",
306				((rid == 1) ? "at 0x" : "0x"),
307				resv->addr);
308		} else {
309			snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
310				((rid == 1) ? "at 0x" : "0x"),
311				resv->addr,
312				(resv->addr + (resv->size - 1)));
313		}
314		eisa_reg_print(child, buf,
315			((rid == 2) ? &separator : NULL), &column);
316	}
317
318	rid = 0;
319	while ((resv = eisa_find_maddr(e_dev, rid++))) {
320		if ((resv->size == 1) ||
321		    (resv->flags & RESVADDR_BITMASK)) {
322			snprintf(buf, sizeof(buf), "%s%lx",
323				((rid == 1) ? "at 0x" : "0x"),
324				resv->addr);
325		} else {
326			snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
327				((rid == 1) ? "at 0x" : "0x"),
328				resv->addr,
329				(resv->addr + (resv->size - 1)));
330		}
331		eisa_reg_print(child, buf,
332			((rid == 2) ? &separator : NULL), &column);
333	}
334
335	rid = 0;
336	while ((irq = eisa_find_irq(e_dev, rid++)) != NULL) {
337		snprintf(buf, sizeof(buf), "irq %d (%s)", irq->irq_no,
338			 (irq->irq_trigger ? "level" : "edge"));
339		eisa_reg_print(child, buf,
340			((rid == 1) ? &separator : NULL), &column);
341	}
342
343	snprintf(buf, sizeof(buf), "on %s slot %d\n",
344		device_get_nameunit(dev), eisa_get_slot(child));
345	eisa_reg_print(child, buf, NULL, &column);
346
347	return (retval);
348}
349
350static struct irq_node *
351eisa_find_irq(struct eisa_device *e_dev, int rid)
352{
353	int i;
354	struct irq_node *irq;
355
356	for (i = 0, irq = TAILQ_FIRST(&e_dev->ioconf.irqs);
357	     i < rid && irq;
358	     i++, irq = TAILQ_NEXT(irq, links))
359		;
360
361	if (irq)
362		return (irq);
363	else
364		return (NULL);
365}
366
367static struct resvaddr *
368eisa_find_maddr(struct eisa_device *e_dev, int rid)
369{
370	int i;
371	struct resvaddr *resv;
372
373	for (i = 0, resv = LIST_FIRST(&e_dev->ioconf.maddrs);
374	     i < rid && resv;
375	     i++, resv = LIST_NEXT(resv, links))
376		;
377
378	return resv;
379}
380
381static struct resvaddr *
382eisa_find_ioaddr(struct eisa_device *e_dev, int rid)
383{
384	int i;
385	struct resvaddr *resv;
386
387	for (i = 0, resv = LIST_FIRST(&e_dev->ioconf.ioaddrs);
388	     i < rid && resv;
389	     i++, resv = LIST_NEXT(resv, links))
390		;
391
392	return resv;
393}
394
395static int
396eisa_read_ivar(device_t dev, device_t child, int which, u_long *result)
397{
398	struct eisa_device *e_dev = device_get_ivars(child);
399	struct irq_node *irq;
400
401	switch (which) {
402	case EISA_IVAR_SLOT:
403		*result = e_dev->ioconf.slot;
404		break;
405
406	case EISA_IVAR_ID:
407		*result = e_dev->id;
408		break;
409
410	case EISA_IVAR_IRQ:
411		/* XXX only first irq */
412		if ((irq = eisa_find_irq(e_dev, 0)) != NULL) {
413			*result = irq->irq_no;
414		} else {
415			*result = -1;
416		}
417		break;
418
419	default:
420		return (ENOENT);
421	}
422
423	return (0);
424}
425
426static int
427eisa_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
428{
429	return (EINVAL);
430}
431
432static struct resource *
433eisa_alloc_resource(device_t dev, device_t child, int type, int *rid,
434		    u_long start, u_long end, u_long count, u_int flags)
435{
436	int isdefault;
437	struct eisa_device *e_dev = device_get_ivars(child);
438	struct resource *rv, **rvp = 0;
439
440	isdefault = (device_get_parent(child) == dev
441		     && start == 0UL && end == ~0UL && count == 1);
442
443	switch (type) {
444	case SYS_RES_IRQ:
445		if (isdefault) {
446			struct irq_node * irq = eisa_find_irq(e_dev, *rid);
447			if (irq == NULL)
448				return 0;
449			start = end = irq->irq_no;
450			count = 1;
451			if (irq->irq_trigger == EISA_TRIGGER_LEVEL) {
452				flags |= RF_SHAREABLE;
453			} else {
454				flags &= ~RF_SHAREABLE;
455			}
456		}
457		break;
458
459	case SYS_RES_MEMORY:
460		if (isdefault) {
461			struct resvaddr *resv;
462
463			resv = eisa_find_maddr(e_dev, *rid);
464			if (!resv)
465				return 0;
466
467			start = resv->addr;
468			end = resv->addr + (resv->size - 1);
469			count = resv->size;
470			rvp = &resv->res;
471		}
472		break;
473
474	case SYS_RES_IOPORT:
475		if (isdefault) {
476			struct resvaddr *resv;
477
478			resv = eisa_find_ioaddr(e_dev, *rid);
479			if (!resv)
480				return 0;
481
482			start = resv->addr;
483			end = resv->addr + (resv->size - 1);
484			count = resv->size;
485			rvp = &resv->res;
486		}
487		break;
488
489	default:
490		return 0;
491	}
492
493	rv = BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
494				 type, rid, start, end, count, flags);
495	if (rvp)
496		*rvp = rv;
497
498	return rv;
499}
500
501static int
502eisa_release_resource(device_t dev, device_t child, int type, int rid,
503		      struct resource *r)
504{
505	int rv;
506	struct eisa_device *e_dev = device_get_ivars(child);
507	struct resvaddr *resv = 0;
508
509	switch (type) {
510	case SYS_RES_IRQ:
511		if (eisa_find_irq(e_dev, rid) == NULL)
512			return EINVAL;
513		break;
514
515	case SYS_RES_MEMORY:
516		if (device_get_parent(child) == dev)
517			resv = eisa_find_maddr(e_dev, rid);
518		break;
519
520
521	case SYS_RES_IOPORT:
522		if (device_get_parent(child) == dev)
523			resv = eisa_find_ioaddr(e_dev, rid);
524		break;
525
526	default:
527		return (ENOENT);
528	}
529
530	rv = BUS_RELEASE_RESOURCE(device_get_parent(dev), child, type, rid, r);
531
532	if (rv == 0) {
533		if (resv)
534			resv->res = 0;
535	}
536
537	return rv;
538}
539
540static int
541eisa_add_intr_m(device_t eisa, device_t dev, int irq, int trigger)
542{
543	struct eisa_device *e_dev = device_get_ivars(dev);
544	struct irq_node *irq_info;
545
546	irq_info = (struct irq_node *)malloc(sizeof(*irq_info), M_DEVBUF,
547					     M_NOWAIT);
548	if (irq_info == NULL)
549		return (1);
550
551	irq_info->irq_no = irq;
552	irq_info->irq_trigger = trigger;
553	irq_info->idesc = NULL;
554	TAILQ_INSERT_TAIL(&e_dev->ioconf.irqs, irq_info, links);
555	return 0;
556}
557
558static int
559eisa_add_resvaddr(struct eisa_device *e_dev, struct resvlist *head, u_long base,
560		  u_long size, int flags)
561{
562	resvaddr_t *reservation;
563
564	reservation = (resvaddr_t *)malloc(sizeof(resvaddr_t),
565					   M_DEVBUF, M_NOWAIT);
566	if(!reservation)
567		return (ENOMEM);
568
569	reservation->addr = base;
570	reservation->size = size;
571	reservation->flags = flags;
572
573	if (!LIST_FIRST(head)) {
574		LIST_INSERT_HEAD(head, reservation, links);
575	}
576	else {
577		resvaddr_t *node;
578		LIST_FOREACH(node, head, links) {
579			if (node->addr > reservation->addr) {
580				/*
581				 * List is sorted in increasing
582				 * address order.
583				 */
584				LIST_INSERT_BEFORE(node, reservation, links);
585				break;
586			}
587
588			if (node->addr == reservation->addr) {
589				/*
590				 * If the entry we want to add
591				 * matches any already in here,
592				 * fail.
593				 */
594				free(reservation, M_DEVBUF);
595				return (EEXIST);
596			}
597
598			if (!LIST_NEXT(node, links)) {
599				LIST_INSERT_AFTER(node, reservation, links);
600				break;
601			}
602		}
603	}
604	return (0);
605}
606
607static int
608eisa_add_mspace_m(device_t eisa, device_t dev, u_long mbase, u_long msize,
609    int flags)
610{
611	struct eisa_device *e_dev = device_get_ivars(dev);
612
613	return	eisa_add_resvaddr(e_dev, &(e_dev->ioconf.maddrs), mbase, msize,
614				  flags);
615}
616
617static int
618eisa_add_iospace_m(device_t eisa, device_t dev, u_long iobase, u_long iosize,
619    int flags)
620{
621	struct eisa_device *e_dev = device_get_ivars(dev);
622
623	return	eisa_add_resvaddr(e_dev, &(e_dev->ioconf.ioaddrs), iobase,
624				  iosize, flags);
625}
626
627static device_method_t eisa_methods[] = {
628	/* Device interface */
629	DEVMETHOD(device_probe,		eisa_probe),
630	DEVMETHOD(device_attach,	bus_generic_attach),
631	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
632	DEVMETHOD(device_suspend,	bus_generic_suspend),
633	DEVMETHOD(device_resume,	bus_generic_resume),
634
635	/* Bus interface */
636	DEVMETHOD(bus_print_child,	eisa_print_child),
637	DEVMETHOD(bus_probe_nomatch,	eisa_probe_nomatch),
638	DEVMETHOD(bus_read_ivar,	eisa_read_ivar),
639	DEVMETHOD(bus_write_ivar,	eisa_write_ivar),
640	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
641	DEVMETHOD(bus_alloc_resource,	eisa_alloc_resource),
642	DEVMETHOD(bus_release_resource,	eisa_release_resource),
643	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
644	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
645	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
646	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
647
648	/* EISA interface */
649	DEVMETHOD(eisa_add_intr,	eisa_add_intr_m),
650	DEVMETHOD(eisa_add_iospace,	eisa_add_iospace_m),
651	DEVMETHOD(eisa_add_mspace,	eisa_add_mspace_m),
652
653	{ 0, 0 }
654};
655
656static driver_t eisa_driver = {
657	"eisa",
658	eisa_methods,
659	1,			/* no softc */
660};
661
662DRIVER_MODULE(eisa, eisab, eisa_driver, eisa_devclass, 0, 0);
663DRIVER_MODULE(eisa, legacy, eisa_driver, eisa_devclass, 0, 0);
664