eisaconf.c revision 31016
190075Sobrien/*
2132718Skan * EISA bus probe and attach routines
390075Sobrien *
490075Sobrien * Copyright (c) 1995, 1996 Justin T. Gibbs.
590075Sobrien * All rights reserved.
690075Sobrien *
790075Sobrien * Redistribution and use in source and binary forms, with or without
890075Sobrien * modification, are permitted provided that the following conditions
990075Sobrien * are met:
1090075Sobrien * 1. Redistributions of source code must retain the above copyright
1190075Sobrien *    notice immediately at the beginning of the file, without modification,
1290075Sobrien *    this list of conditions, and the following disclaimer.
1390075Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1490075Sobrien *    notice, this list of conditions and the following disclaimer in the
1590075Sobrien *    documentation and/or other materials provided with the distribution.
1690075Sobrien * 3. The name of the author may not be used to endorse or promote products
1790075Sobrien *    derived from this software without specific prior written permission.
1890075Sobrien *
1990075Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2090075Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2190075Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22132718Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2390075Sobrien * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24132718Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25132718Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26117395Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2790075Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28132718Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29132718Skan * SUCH DAMAGE.
30117395Skan *
3190075Sobrien *	$Id: eisaconf.c,v 1.32 1997/10/28 15:58:08 bde Exp $
32132718Skan */
33117395Skan
3490075Sobrien#include "opt_eisa.h"
35132718Skan
36117395Skan#include <sys/param.h>
3790075Sobrien#include <sys/systm.h>
38132718Skan#include <sys/kernel.h>
39117395Skan#include <sys/malloc.h>
4090075Sobrien
41132718Skan#include <machine/limits.h>
42117395Skan
4390075Sobrien#include <i386/eisa/eisaconf.h>
44132718Skan
45132718Skan#include <sys/interrupt.h>
46117395Skan
4790075Sobrienstruct eisa_device_node{
48132718Skan	struct	eisa_device dev;
49132718Skan	struct	eisa_device_node *next;
50117395Skan};
5190075Sobrien
52132718Skan/*
53132718Skan * This should probably be a list of "struct device" once it exists.
54117395Skan * A struct device will incorperate ioconf and driver entry point data
5590075Sobrien * regardless of how its attached to the system (via unions) as well
56132718Skan * as more generic information that all device types should support (unit
57132718Skan * number, if its installed, etc).
58117395Skan */
5990075Sobrienstatic struct eisa_device_node *eisa_dev_list;
60132718Skanstatic struct eisa_device_node **eisa_dev_list_tail = &eisa_dev_list;
61132718Skanstatic u_long eisa_unit;
62117395Skan
6390075Sobrienstatic struct eisa_driver mainboard_drv = {
64132718Skan				     "eisa",
65132718Skan				     NULL,
66117395Skan				     NULL,
6790075Sobrien				     NULL,
68132718Skan				     &eisa_unit
69132718Skan				   };
70132718Skan
71132718Skan/*
7290075Sobrien * Add the mainboard_drv to the eisa driver linkerset so that it is
73132718Skan * defined even if no EISA drivers are linked into the kernel.
74 */
75DATA_SET (eisadriver_set, mainboard_drv);
76
77/*
78 * Local function declarations and static variables
79 */
80void eisa_reg_print __P((struct eisa_device *e_dev, char *string,
81			 char *separator));
82static int eisa_add_resvaddr __P((struct eisa_device *e_dev,
83				  struct resvlist *head, u_long	base,
84				  u_long size, int flags));
85static int eisa_reg_resvaddr __P((struct eisa_device *e_dev,
86				  struct resvlist *head, resvaddr_t *resvaddr,
87				  int *reg_count));
88
89/*
90 * Keep some state about what we've printed so far
91 * to make probe output pretty.
92 */
93static struct {
94	int	in_registration;/* reg_start has been called */
95	int	num_interrupts;
96	int	num_ioaddrs;
97	int	num_maddrs;
98	int	column;		/* How much we have output so far. */
99#define	MAX_COL 80
100} reg_state;
101
102/* Global variable, so UserConfig can change it. */
103#ifndef EISA_SLOTS
104#define EISA_SLOTS 10   /* PCI clashes with higher ones.. fix later */
105#endif
106int num_eisa_slots = EISA_SLOTS;
107
108/*
109** probe for EISA devices
110*/
111void
112eisa_configure()
113{
114	int i,slot;
115	struct eisa_device_node *dev_node;
116	struct eisa_driver **e_drvp;
117	struct eisa_driver *e_drv;
118	struct eisa_device *e_dev;
119	int eisaBase = 0xc80;
120	eisa_id_t eisa_id;
121
122	e_drvp = (struct eisa_driver**)eisadriver_set.ls_items;
123
124	for (slot = 0; slot < num_eisa_slots; eisaBase+=0x1000, slot++) {
125		int id_size = sizeof(eisa_id);
126		eisa_id = 0;
127    		for( i = 0; i < id_size; i++ ) {
128			outb(eisaBase,0x80 + i); /*Some cards require priming*/
129			eisa_id |= inb(eisaBase+i) << ((id_size-i-1)*CHAR_BIT);
130		}
131		if (eisa_id & 0x80000000)
132			continue;  /* no EISA card in slot */
133
134		/* Prepare an eisa_device_node for this slot */
135		dev_node = (struct eisa_device_node *)malloc(sizeof(*dev_node),
136							    M_DEVBUF, M_NOWAIT);
137		if (!dev_node) {
138			printf("eisa0: cannot malloc eisa_device_node");
139			break; /* Try to attach what we have already */
140		}
141		bzero(dev_node, sizeof(*dev_node));
142		e_dev = &(dev_node->dev);
143
144		e_dev->id = eisa_id;
145
146		e_dev->full_name = "Unattached Device";
147
148		e_dev->ioconf.slot = slot;
149
150		/* Initialize our lists of reserved addresses */
151		LIST_INIT(&(e_dev->ioconf.ioaddrs));
152		LIST_INIT(&(e_dev->ioconf.maddrs));
153		TAILQ_INIT(&(e_dev->ioconf.irqs));
154
155		*eisa_dev_list_tail = dev_node;
156		eisa_dev_list_tail = &dev_node->next;
157	}
158
159	dev_node = eisa_dev_list;
160
161	/*
162	 * "Attach" the system board
163	 */
164
165	/* The first will be the motherboard in a true EISA system */
166	if (dev_node && (dev_node->dev.ioconf.slot == 0)) {
167		char *idstring;
168
169		e_dev = &dev_node->dev;
170		e_dev->driver = &mainboard_drv;
171		e_dev->unit = (*e_dev->driver->unit)++;
172		idstring = (char *)malloc(8 + sizeof(" (System Board)") + 1,
173					  M_DEVBUF, M_NOWAIT);
174		if (idstring == NULL) {
175			panic("Eisa probe unable to malloc");
176		}
177		sprintf(idstring, "%c%c%c%x%x (System Board)",
178			EISA_MFCTR_CHAR0(e_dev->id),
179			EISA_MFCTR_CHAR1(e_dev->id),
180			EISA_MFCTR_CHAR2(e_dev->id),
181			EISA_PRODUCT_ID(e_dev->id),
182			EISA_REVISION_ID(e_dev->id));
183		e_dev->full_name = idstring;
184
185		printf("%s%ld: <%s>\n",
186		       e_dev->driver->name,
187		       e_dev->unit,
188		       e_dev->full_name);
189
190		/* Should set the iosize, but I don't have a spec handy */
191		printf("Probing for devices on the EISA bus\n");
192		dev_node = dev_node->next;
193	}
194
195	if (!eisa_dev_list) {
196		/*
197		 * No devices.
198		 */
199		return;
200    	}
201	/*
202	 * See what devices we recognize.
203	 */
204	while((e_drv = *e_drvp++)) {
205		if (e_drv->probe)
206			(*e_drv->probe)();
207	}
208
209	/*
210	 * Attach the devices we found in slot order
211	 */
212	for (; dev_node; dev_node=dev_node->next) {
213		e_dev = &dev_node->dev;
214		e_drv = e_dev->driver;
215
216		if (e_drv) {
217			/*
218			 * Determine the proper unit number for this device.
219			 * Here we should look in the device table generated
220			 * by config to see if this type of device is enabled
221			 * either generically or for this particular address
222			 * as well as determine if a reserved unit number
223			 * should be used.  We should also ensure that the
224			 * "next availible unit number" skips over "wired" unit
225			 * numbers. This will be done after config is fixed or
226			 * some other configuration method is chosen.
227			 */
228			e_dev->unit = (*e_drv->unit)++;
229			if ((*e_drv->attach)(e_dev) < 0) {
230				/* Ensure registration has ended */
231				reg_state.in_registration = 0;
232				printf("\n%s0:%d <%s> attach failed\n",
233					mainboard_drv.name,
234					e_dev->ioconf.slot,
235					e_dev->full_name);
236				continue;
237			}
238			/* Ensure registration has ended */
239			reg_state.in_registration = 0;
240		}
241		else {
242			/* Announce unattached device */
243			printf("%s0:%d <%c%c%c%x%x=0x%x> unknown device\n",
244				mainboard_drv.name,
245				e_dev->ioconf.slot,
246				EISA_MFCTR_CHAR0(e_dev->id),
247				EISA_MFCTR_CHAR1(e_dev->id),
248				EISA_MFCTR_CHAR2(e_dev->id),
249				EISA_PRODUCT_ID(e_dev->id),
250				EISA_REVISION_ID(e_dev->id),
251				e_dev->id);
252		}
253	}
254}
255
256struct eisa_device *
257eisa_match_dev(e_dev, match_func)
258	struct eisa_device *e_dev;
259	const char* (*match_func)(eisa_id_t);
260{
261	struct eisa_device_node *e_node = eisa_dev_list;
262
263	if (e_dev) {
264		/* Start our search from the last successful match */
265		e_node = ((struct eisa_device_node *)e_dev)->next;
266	}
267
268	for(; e_node; e_node = e_node->next) {
269		const char *result;
270		if (e_node->dev.driver) {
271			/* Already claimed */
272			continue;
273		}
274		result = (*match_func)(e_node->dev.id);
275		if (result) {
276			e_node->dev.full_name = result;
277			return (&(e_node->dev));
278		}
279	}
280	return NULL;
281}
282
283/* Interrupt and I/O space registration facitlities */
284void
285eisa_reg_start(e_dev)
286	struct eisa_device *e_dev;
287{
288	/*
289	 * Announce the device.
290	 */
291	char *string;
292
293	reg_state.in_registration = 1;
294	reg_state.num_interrupts = 0;
295	reg_state.num_ioaddrs = 0;
296	reg_state.num_maddrs = 0;
297	reg_state.column = 0;
298
299	string = malloc(strlen(e_dev->full_name) + sizeof(" <>") + /*NULL*/1,
300			M_TEMP, M_NOWAIT);
301	if(!string) {
302		printf("eisa0: cannot malloc device description string\n");
303		return;
304	}
305	sprintf(string, " <%s>", e_dev->full_name);
306	eisa_reg_print(e_dev, string, /*separator=*/NULL);
307	free(string, M_TEMP);
308}
309
310/*
311 * Output registration information mindfull of screen wrap.
312 * Output an optional character separator before the string
313 * if the line does not wrap.
314 */
315void
316eisa_reg_print(e_dev, string, separator)
317	struct eisa_device *e_dev;
318	char *string;
319	char *separator;
320{
321	int len = strlen(string);
322
323	if(separator)
324		len++;
325
326	if(reg_state.column + len > MAX_COL) {
327		printf("\n");
328		reg_state.column = 0;
329	}
330	else if(separator) {
331		printf("%c", *separator);
332		reg_state.column++;
333	}
334
335	if(reg_state.column == 0)
336		reg_state.column += printf("%s%ld:%s",
337					   e_dev->driver->name,
338					   e_dev->unit,
339					   string);
340	else
341		reg_state.column += printf("%s", string);
342}
343
344/* Interrupt and I/O space registration facitlities */
345void
346eisa_reg_end(e_dev)
347	struct eisa_device *e_dev;
348{
349	if( reg_state.in_registration )
350	{
351		char string[25];
352
353		sprintf(string, " on %s0 slot %d",
354			mainboard_drv.name,
355			e_dev->ioconf.slot);
356		eisa_reg_print(e_dev, string, NULL);
357		printf("\n");
358		reg_state.in_registration = 0;
359	}
360	else
361		printf("eisa_reg_end called outside of a "
362		       "registration session\n");
363}
364
365int
366eisa_add_intr(e_dev, irq)
367	struct eisa_device *e_dev;
368	int irq;
369{
370	struct	irq_node *irq_info;
371
372	irq_info = (struct irq_node *)malloc(sizeof(*irq_info), M_DEVBUF,
373					     M_NOWAIT);
374	if (irq_info == NULL)
375		return (1);
376
377	irq_info->irq_no = irq;
378	irq_info->idesc = NULL;
379	TAILQ_INSERT_TAIL(&e_dev->ioconf.irqs, irq_info, links);
380	return 0;
381}
382
383int
384eisa_reg_intr(e_dev, irq, func, arg, maskptr, shared)
385	struct eisa_device *e_dev;
386	int   irq;
387	void (*func)(void *);
388	void  *arg;
389	u_int *maskptr;
390	int   shared;
391{
392	char string[25];
393	char separator = ',';
394
395#if NOT_YET
396	/*
397	 * Punt on conflict detection for the moment.
398	 * I want to develop a generic routine to do
399	 * this for all device types.
400	 */
401	int checkthese = CC_IRQ;
402	if (haveseen_dev(dev, checkthese))
403        	return 1;
404#endif
405	if (reg_state.in_registration) {
406		/*
407		 * Find the first instance of this irq that has a
408		 * NULL idesc.
409		 */
410		struct irq_node *cur_irq;
411
412		cur_irq = TAILQ_FIRST(&e_dev->ioconf.irqs);
413		while (cur_irq != NULL) {
414			if (cur_irq->irq_no == irq
415			 && cur_irq->idesc == NULL) {
416				/* XXX use cfg->devdata  */
417                		void *dev_instance = (void *)-1;
418
419				cur_irq->idesc = intr_create(dev_instance,
420							     irq,
421							     func,
422							     arg,
423							     maskptr, 0);
424				break;
425			}
426			cur_irq = TAILQ_NEXT(cur_irq, links);
427		}
428
429		if (cur_irq == NULL || cur_irq->idesc == NULL)
430			return (-1);
431	} else {
432		return EPERM;
433	}
434
435	sprintf(string, " irq %d", irq);
436	eisa_reg_print(e_dev, string, reg_state.num_interrupts ?
437				      &separator : NULL);
438	reg_state.num_interrupts++;
439	return (0);
440}
441
442int
443eisa_release_intr(e_dev, irq, func)
444	struct eisa_device *e_dev;
445	int   irq;
446	void  (*func)(void *);
447{
448	int	result;
449	struct	irq_node *cur_irq;
450
451	result = -1;
452	cur_irq = TAILQ_FIRST(&e_dev->ioconf.irqs);
453       	while (cur_irq != NULL) {
454		if (cur_irq->irq_no == irq) {
455			if (cur_irq->idesc != NULL)
456				intr_destroy(cur_irq->idesc);
457			cur_irq = TAILQ_NEXT(cur_irq, links);
458			TAILQ_REMOVE(&e_dev->ioconf.irqs, cur_irq, links);
459			result = 0;
460		} else {
461			cur_irq = TAILQ_NEXT(cur_irq, links);
462		}
463	}
464	if (result != 0) {
465		printf("%s%ld: Attempted to release an interrupt (%d) "
466		       "it doesn't own\n", e_dev->driver->name,
467			e_dev->unit, irq);
468	}
469
470	return (result);
471}
472
473int
474eisa_enable_intr(e_dev, irq)
475	struct eisa_device *e_dev;
476	int irq;
477{
478	struct	irq_node *cur_irq;
479	int	result;
480
481	result = -1;
482	cur_irq = TAILQ_FIRST(&e_dev->ioconf.irqs);
483       	while (cur_irq != NULL) {
484		if (cur_irq->irq_no == irq
485		 && cur_irq->idesc != NULL) {
486			result = intr_connect(cur_irq->idesc);
487		}
488		cur_irq = TAILQ_NEXT(cur_irq, links);
489	}
490	return (result);
491}
492
493static int
494eisa_add_resvaddr(e_dev, head, base, size, flags)
495	struct eisa_device *e_dev;
496	struct resvlist *head;
497	u_long	base;
498	u_long	size;
499	int	flags;
500{
501	resvaddr_t *reservation;
502
503	reservation = (resvaddr_t *)malloc(sizeof(resvaddr_t),
504					   M_DEVBUF, M_NOWAIT);
505	if(!reservation)
506		return (ENOMEM);
507
508	reservation->addr = base;
509	reservation->size = size;
510	reservation->flags = flags;
511
512	if (!head->lh_first) {
513		LIST_INSERT_HEAD(head, reservation, links);
514	}
515	else {
516		resvaddr_t *node;
517		for(node = head->lh_first; node; node = node->links.le_next) {
518			if (node->addr > reservation->addr) {
519				/*
520				 * List is sorted in increasing
521				 * address order.
522				 */
523				LIST_INSERT_BEFORE(node, reservation, links);
524				break;
525			}
526
527			if (node->addr == reservation->addr) {
528				/*
529				 * If the entry we want to add
530				 * matches any already in here,
531				 * fail.
532				 */
533				free(reservation, M_DEVBUF);
534				return (EEXIST);
535			}
536
537			if (!node->links.le_next) {
538				LIST_INSERT_AFTER(node, reservation, links);
539				break;
540			}
541		}
542	}
543	return (0);
544}
545
546int
547eisa_add_mspace(e_dev, mbase, msize, flags)
548	struct eisa_device *e_dev;
549	u_long	mbase;
550	u_long	msize;
551	int	flags;
552{
553	return	eisa_add_resvaddr(e_dev, &(e_dev->ioconf.maddrs), mbase, msize,
554				  flags);
555}
556
557int
558eisa_add_iospace(e_dev, iobase, iosize, flags)
559	struct eisa_device *e_dev;
560	u_long	iobase;
561	u_long	iosize;
562	int	flags;
563{
564	return	eisa_add_resvaddr(e_dev, &(e_dev->ioconf.ioaddrs), iobase,
565				  iosize, flags);
566}
567
568static int
569eisa_reg_resvaddr(e_dev, head, resvaddr, reg_count)
570	struct eisa_device *e_dev;
571	struct resvlist *head;
572	resvaddr_t *resvaddr;
573	int *reg_count;
574{
575	if (reg_state.in_registration) {
576		resvaddr_t *node;
577		/*
578		 * Ensure that this resvaddr is actually in the devices'
579		 * reservation list.
580		 */
581		for(node = head->lh_first; node;
582		    node = node->links.le_next) {
583			if (node == resvaddr) {
584				char buf[35];
585				char separator = ',';
586				char *string = buf;
587
588				if (*reg_count == 0) {
589					/* First time */
590					string += sprintf(string, " at");
591				}
592
593				if (node->size == 1
594				  || (node->flags & RESVADDR_BITMASK))
595					sprintf(string, " 0x%lx", node->addr);
596				else
597					sprintf(string, " 0x%lx-0x%lx",
598						node->addr,
599						node->addr + node->size - 1);
600				eisa_reg_print(e_dev, buf,
601						*reg_count ? &separator : NULL);
602				(*reg_count)++;
603				return (0);
604			}
605		}
606		return (ENOENT);
607	}
608	return EPERM;
609}
610
611int
612eisa_reg_mspace(e_dev, resvaddr)
613	struct eisa_device *e_dev;
614	resvaddr_t *resvaddr;
615{
616#ifdef NOT_YET
617	/*
618	 * Punt on conflict detection for the moment.
619	 * I want to develop a generic routine to do
620	 * this for all device types.
621	 */
622	int checkthese = CC_MADDR;
623	if (haveseen_dev(dev, checkthese))
624		return -1;
625#endif
626	return (eisa_reg_resvaddr(e_dev, &(e_dev->ioconf.maddrs), resvaddr,
627				  &(reg_state.num_maddrs)));
628}
629
630int
631eisa_reg_iospace(e_dev, resvaddr)
632	struct eisa_device *e_dev;
633	resvaddr_t *resvaddr;
634{
635#ifdef NOT_YET
636	/*
637	 * Punt on conflict detection for the moment.
638	 * I want to develop a generic routine to do
639	 * this for all device types.
640	 */
641	int checkthese = CC_IOADDR;
642	if (haveseen_dev(dev, checkthese))
643		return -1;
644#endif
645	return (eisa_reg_resvaddr(e_dev, &(e_dev->ioconf.ioaddrs), resvaddr,
646				  &(reg_state.num_ioaddrs)));
647}
648
649int
650eisa_registerdev(e_dev, driver)
651	struct eisa_device *e_dev;
652	struct eisa_driver *driver;
653{
654	e_dev->driver = driver;	/* Driver now owns this device */
655	return (0);
656}
657
658