pci.c revision 3870
1/**************************************************************************
2**
3**  $Id: pci.c,v 1.7 1994/10/12 02:33:21 se Exp $
4**
5**  General subroutines for the PCI bus on 80*86 systems.
6**  pci_configure ()
7**
8**  386bsd / FreeBSD
9**
10**-------------------------------------------------------------------------
11**
12** Copyright (c) 1994 Wolfgang Stanglmeier.  All rights reserved.
13**
14** Redistribution and use in source and binary forms, with or without
15** modification, are permitted provided that the following conditions
16** are met:
17** 1. Redistributions of source code must retain the above copyright
18**    notice, this list of conditions and the following disclaimer.
19** 2. Redistributions in binary form must reproduce the above copyright
20**    notice, this list of conditions and the following disclaimer in the
21**    documentation and/or other materials provided with the distribution.
22** 3. The name of the author may not be used to endorse or promote products
23**    derived from this software without specific prior written permission.
24**
25** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35**
36***************************************************************************
37*/
38
39#include <pci.h>
40#if NPCI > 0
41
42#ifndef __FreeBSD2__
43#if __FreeBSD__ >= 2
44#define	__FreeBSD2__
45#endif
46#endif
47
48/*========================================================
49**
50**	#includes  and  declarations
51**
52**========================================================
53*/
54
55#include <sys/param.h>
56#include <sys/systm.h>
57#include <sys/malloc.h>
58#include <sys/errno.h>
59
60#include <vm/vm.h>
61#include <vm/vm_param.h>
62
63#include <i386/isa/isa.h>
64#include <i386/isa/isa_device.h>
65#include <i386/isa/icu.h>
66#include <i386/pci/pcireg.h>
67
68/*
69**	Function prototypes missing in system headers
70*/
71
72#ifndef __FreeBSD2__
73extern	pmap_t pmap_kernel(void);
74static	vm_offset_t pmap_mapdev (vm_offset_t paddr, vm_size_t vsize);
75
76/*
77 * Type of the first (asm) part of an interrupt handler.
78 */
79typedef void inthand_t __P((u_int cs, u_int ef, u_int esp, u_int ss));
80
81/*
82 * Usual type of the second (C) part of an interrupt handler.  Some bogus
83 * ones need the arg to be the interrupt frame (and not a copy of it, which
84 * is all that is possible in C).
85 */
86typedef void inthand2_t __P((int unit));
87
88/*
89**	XXX	@FreeBSD2@
90**
91**	Unfortunately, the mptr argument is _no_ pointer in 2.0 FreeBSD.
92**	We would prefer a pointer because it enables us to install
93**	new interrupt handlers at any time.
94**	(This is just going to be changed ... <se> :)
95**	In 2.0 FreeBSD later installed interrupt handlers may change
96**	the xyz_imask, but this would not be recognized by handlers
97**	which are installed before.
98*/
99
100static int
101register_intr __P((int intr, int device_id, unsigned int flags,
102		       inthand2_t *handler, unsigned int * mptr, int unit));
103extern unsigned intr_mask[ICU_LEN];
104
105#endif /* !__FreeBSD2__ */
106
107/*========================================================
108**
109**	Autoconfiguration of pci devices.
110**
111**	This is reverse to the isa configuration.
112**	(1) find a pci device.
113**	(2) look for a driver.
114**
115**========================================================
116*/
117
118/*--------------------------------------------------------
119**
120**	The pci devices can be mapped to any address.
121**	As default we start at the last gigabyte.
122**
123**--------------------------------------------------------
124*/
125
126#ifndef PCI_PMEM_START
127#define PCI_PMEM_START 0xc0000000
128#endif
129
130static	vm_offset_t pci_paddr = PCI_PMEM_START;
131
132/*--------------------------------------------------------
133**
134**	The pci device interrupt lines should have been
135**	assigned by the bios. But if the bios failed to
136**	to it, we set it.
137**
138**--------------------------------------------------------
139*/
140
141#ifndef PCI_IRQ
142#define PCI_IRQ 0
143#endif
144
145static	u_long      pci_irq   = PCI_IRQ;
146
147/*---------------------------------------------------------
148**
149**	pci_configure ()
150**
151**	Probe all devices on pci bus and attach them.
152**
153**	May be called more than once.
154**	Any device is attached only once.
155**	(Attached devices are remembered in pci_seen.)
156**
157**---------------------------------------------------------
158*/
159
160static void not_supported (pcici_t tag, u_long type);
161
162static unsigned long pci_seen[NPCI];
163
164static int pci_conf_count;
165
166void pci_configure()
167{
168	u_char	device,last_device;
169	u_short	bus;
170	pcici_t	tag;
171	pcidi_t type;
172	u_long	data;
173	int	unit;
174	int	pci_mechanism;
175	int	pciint;
176	int	irq;
177	char*	name=0;
178	int	newdev=0;
179
180	struct pci_driver *drp=0;
181	struct pci_device *dvp;
182
183	/*
184	**	check pci bus present
185	*/
186
187	pci_mechanism = pci_conf_mode ();
188	if (!pci_mechanism) return;
189	last_device = pci_mechanism==1 ? 31 : 15;
190
191	/*
192	**	hello world ..
193	*/
194
195
196	for (bus=0;bus<NPCI;bus++) {
197#ifndef PCI_QUIET
198	    printf ("pci%d: scanning device 0..%d, mechanism=%d.\n",
199		bus, last_device, pci_mechanism);
200#endif
201	    for (device=0; device<=last_device; device ++) {
202
203		if (pci_seen[bus] & (1ul << device))
204			continue;
205
206		tag = pcitag (bus, device, 0);
207		type = pci_conf_read (tag, PCI_ID_REG);
208
209		if ((!type) || (type==0xfffffffful)) continue;
210
211		/*
212		**	lookup device in ioconfiguration:
213		*/
214
215		for (dvp = pci_devtab; dvp->pd_name; dvp++) {
216			drp = dvp->pd_driver;
217			if (!drp)
218				continue;
219			if ((name=(*drp->probe)(tag, type)))
220				break;
221		};
222
223		if (!dvp->pd_name) {
224#ifndef PCI_QUIET
225			if (pci_conf_count)
226				continue;
227			printf("pci%d:%d: ", bus, device);
228			not_supported (tag, type);
229#endif
230			continue;
231		};
232
233		pci_seen[bus] |= (1ul << device);
234		/*
235		**	Get and increment the unit.
236		*/
237
238		unit = (*drp->count)++;
239
240		/*
241		**	ignore device ?
242		*/
243
244		if (!*name) continue;
245
246		/*
247		**	Announce this device
248		*/
249
250		newdev++;
251		printf ("%s%d <%s>", dvp->pd_name, unit, name);
252
253		/*
254		**	Get the int pin number (pci interrupt number a-d)
255		**	from the pci configuration space.
256		*/
257
258		data = pci_conf_read (tag, PCI_INTERRUPT_REG);
259		pciint = PCI_INTERRUPT_PIN_EXTRACT(data);
260
261		if (pciint) {
262
263			printf (" int %c", 0x60+pciint);
264
265			/*
266			**	If the interrupt line register is not set,
267			**	set it now from PCI_IRQ.
268			*/
269
270			if (!(PCI_INTERRUPT_LINE_EXTRACT(data))) {
271
272				irq = pci_irq & 0x0f;
273				pci_irq >>= 4;
274
275				data = PCI_INTERRUPT_LINE_INSERT(data, irq);
276				printf (" (config)");
277				pci_conf_write (tag, PCI_INTERRUPT_REG, data);
278			};
279
280			irq = PCI_INTERRUPT_LINE_EXTRACT(data);
281
282			/*
283			**	If it's zero, the isa irq number is unknown,
284			**	and we cannot bind the pci interrupt to isa.
285			*/
286
287			if (irq)
288				printf (" irq %d", irq);
289			else
290				printf (" not bound");
291		};
292
293		/*
294		**	enable memory access
295		*/
296
297		data = (pci_conf_read (tag, PCI_COMMAND_STATUS_REG)
298			& 0xffff) | PCI_COMMAND_MEM_ENABLE;
299
300		pci_conf_write (tag, (u_char) PCI_COMMAND_STATUS_REG, data);
301
302		/*
303		**	attach device
304		**	may produce additional log messages,
305		**	i.e. when installing subdevices.
306		*/
307
308		printf (" on pci%d:%d\n", bus, device);
309
310		(*drp->attach) (tag, unit);
311	    };
312	};
313
314#ifndef PCI_QUIET
315	if (newdev)
316		printf ("pci uses physical addresses from 0x%lx to 0x%lx\n",
317			(u_long)PCI_PMEM_START, (u_long)pci_paddr);
318#endif
319	pci_conf_count++;
320}
321
322/*-----------------------------------------------------------------------
323**
324**	Map device into port space.
325**
326**	PCI-Specification:  6.2.5.1: address maps
327**
328**-----------------------------------------------------------------------
329*/
330
331int pci_map_port (pcici_t tag, u_long reg, u_short* pa)
332{
333	/*
334	**	@MAPIO@ not yet implemented.
335	*/
336	printf ("pci_map_port failed: not yet implemented\n");
337	return (0);
338}
339
340/*-----------------------------------------------------------------------
341**
342**	Map device into virtual and physical space
343**
344**	PCI-Specification:  6.2.5.1: address maps
345**
346**-----------------------------------------------------------------------
347*/
348
349int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa)
350{
351	u_long data;
352	vm_size_t vsize;
353	vm_offset_t vaddr;
354
355	/*
356	**	sanity check
357	*/
358
359        if (reg < PCI_MAP_REG_START || reg >= PCI_MAP_REG_END || (reg & 3)) {
360        	printf ("pci_map_mem failed: bad register=0x%x\n",
361               		(unsigned)reg);
362                return (0);
363	};
364
365	/*
366	**	get size and type of memory
367	**
368	**	type is in the lowest four bits.
369	**	If device requires 2^n bytes, the next
370	**	n-4 bits are read as 0.
371	*/
372
373	pci_conf_write (tag, reg, 0xfffffffful);
374	data = pci_conf_read (tag, reg);
375
376	switch (data & 0x0f) {
377
378	case PCI_MAP_MEMORY_TYPE_32BIT:	/* 32 bit non cachable */
379		break;
380
381	default:	/* unknown */
382                printf ("pci_map_mem failed: bad memory type=0x%x\n",
383               		(unsigned) data);
384                return (0);
385	};
386
387	/*
388	**	mask out the type,
389	**	and round up to a page size
390	*/
391
392	vsize = round_page (-(data &  PCI_MAP_MEMORY_ADDRESS_MASK));
393
394	if (!vsize) return (0);
395
396	/*
397	**	align physical address to virtual size
398	*/
399
400	if ((data = pci_paddr % vsize))
401		pci_paddr += vsize - data;
402
403	vaddr = (vm_offset_t) pmap_mapdev (pci_paddr, vsize);
404
405
406	if (!vaddr) return (0);
407
408#ifndef PCI_QUIET
409	/*
410	**	display values.
411	*/
412
413	printf ("\treg%d: virtual=0x%lx physical=0x%lx\n",
414		(unsigned) reg, (u_long)vaddr, (u_long)pci_paddr);
415#endif
416
417	/*
418	**	return them to the driver
419	*/
420
421	*va = vaddr;
422	*pa = pci_paddr;
423
424	/*
425	**	set device address
426	*/
427
428	pci_conf_write (tag, reg, pci_paddr);
429
430	/*
431	**	and don't forget to increment pci_paddr
432	*/
433
434	pci_paddr += vsize;
435
436	return (1);
437}
438
439/*-----------------------------------------------------------------------
440**
441**	Map pci interrupts to isa interrupts.
442**
443**-----------------------------------------------------------------------
444*/
445
446static	unsigned int	pci_int_mask [16];
447
448int pci_map_int (pcici_t tag, int(*func)(), void* arg, unsigned* maskptr)
449{
450	int irq;
451	unsigned mask;
452
453	irq = PCI_INTERRUPT_LINE_EXTRACT(
454		pci_conf_read (tag, PCI_INTERRUPT_REG));
455
456	if (irq >= 16 || irq <= 0) {
457		printf ("pci_map_int failed: no int line set.\n");
458		return (0);
459	}
460
461	mask = 1ul << irq;
462
463	if (!maskptr)
464		maskptr = &pci_int_mask[irq];
465
466	INTRMASK (*maskptr, mask);
467
468	register_intr(
469		irq,		/* isa irq	*/
470		0,		/* deviced??	*/
471		0,		/* flags?	*/
472		(inthand2_t*) func, /* handler	*/
473		maskptr,	/* mask pointer	*/
474		(int) arg);	/* handler arg	*/
475
476#ifdef __FreeBSD2__
477	/*
478	**	XXX See comment at beginning of file.
479	**
480	**	Have to update all the interrupt masks ... Grrrrr!!!
481	*/
482	{
483		unsigned * mp = &intr_mask[0];
484		/*
485		**	update the isa interrupt masks.
486		*/
487		for (mp=&intr_mask[0]; mp<&intr_mask[ICU_LEN]; mp++)
488			if (*mp & *maskptr)
489				*mp |= mask;
490		/*
491		**	update the pci interrupt masks.
492		*/
493		for (mp=&pci_int_mask[0]; mp<&pci_int_mask[16]; mp++)
494			if (*mp & *maskptr)
495				*mp |= mask;
496	};
497#endif
498
499	INTREN (mask);
500
501	return (1);
502}
503
504/*-----------------------------------------------------------
505**
506**	Display of unknown devices.
507**
508**-----------------------------------------------------------
509*/
510struct vt {
511	u_short	ident;
512	char*	name;
513};
514
515static struct vt VendorTable[] = {
516	{0x1002, "ATI TECHNOLOGIES INC"},
517	{0x1011, "DIGITAL EQUIPMENT CORPORATION"},
518	{0x101A, "NCR"},
519	{0x102B, "MATROX"},
520	{0x1045, "OPTI"},
521	{0x5333, "S3 INC."},
522	{0x8086, "INTEL CORPORATION"},
523	{0,0}
524};
525
526static const char *const majclasses[] = {
527	"old", "storage", "network", "display",
528	"multimedia", "memory", "bridge"
529};
530
531void not_supported (pcici_t tag, u_long type)
532{
533	u_char	reg;
534	u_long	data;
535	struct vt * vp;
536
537	/*
538	**	lookup the names.
539	*/
540
541	for (vp=VendorTable; vp->ident; vp++)
542		if (vp->ident == (type & 0xffff))
543			break;
544
545	/*
546	**	and display them.
547	*/
548
549	if (vp->ident) printf (vp->name);
550		else   printf ("vendor=0x%lx", type & 0xffff);
551
552	printf (", device=0x%lx", type >> 16);
553
554	data = (pci_conf_read(tag, PCI_CLASS_REG) >> 24) & 0xff;
555	if (data < sizeof(majclasses) / sizeof(majclasses[0]))
556		printf(", class=%s", majclasses[data]);
557
558	printf (" [not supported]\n");
559
560	for (reg=PCI_MAP_REG_START; reg<PCI_MAP_REG_END; reg+=4) {
561		data = pci_conf_read (tag, reg);
562		if (!data) continue;
563		switch (data&7) {
564
565		case 1:
566		case 5:
567			printf ("	map(%x): io(%lx)\n",
568				reg, data & ~3);
569			break;
570		case 0:
571			printf ("	map(%x): mem32(%lx)\n",
572				reg, data & ~7);
573			break;
574		case 2:
575			printf ("	map(%x): mem20(%lx)\n",
576				reg, data & ~7);
577			break;
578		case 4:
579			printf ("	map(%x): mem64(%lx)\n",
580				reg, data & ~7);
581			break;
582		}
583	}
584}
585
586#ifndef __FreeBSD2__
587/*-----------------------------------------------------------
588**
589**	Mapping of physical to virtual memory
590**
591**-----------------------------------------------------------
592*/
593
594extern vm_map_t kernel_map;
595
596static	vm_offset_t pmap_mapdev (vm_offset_t paddr, vm_size_t vsize)
597{
598	vm_offset_t	vaddr,value;
599	u_long		result;
600
601	vaddr  = vm_map_min (kernel_map);
602
603	result = vm_map_find (kernel_map, (void*)0, (vm_offset_t) 0,
604				&vaddr, vsize, TRUE);
605
606	if (result != KERN_SUCCESS) {
607		printf (" vm_map_find failed(%d)\n", result);
608		return (0);
609	};
610
611	/*
612	**	map physical
613	*/
614
615	value = vaddr;
616	while (vsize >= NBPG) {
617		pmap_enter (pmap_kernel(), vaddr, paddr,
618				VM_PROT_READ|VM_PROT_WRITE, TRUE);
619		vaddr += NBPG;
620		paddr += NBPG;
621		vsize -= NBPG;
622	};
623	return (value);
624}
625
626/*------------------------------------------------------------
627**
628**	Emulate the register_intr() function of FreeBSD 2.0
629**
630**	requires a patch:
631**	FreeBSD 2.0:	"/sys/i386/isa/vector.s"
632**	386bsd0.1:	"/sys/i386/isa/icu.s"
633**	386bsd1.0:	Please ask Jesus Monroy Jr.
634**
635**------------------------------------------------------------
636*/
637
638#include <machine/segments.h>
639
640int		pci_int_unit [16];
641inthand2_t*    (pci_int_hdlr [16]);
642unsigned int *	pci_int_mptr [16];
643unsigned int	pci_int_count[16];
644
645extern void
646	Vpci3(), Vpci4(), Vpci5(), Vpci6(), Vpci7(), Vpci8(), Vpci9(),
647	Vpci10(), Vpci11(), Vpci12(), Vpci13(), Vpci14(), Vpci15();
648
649static inthand_t* pci_int_glue[16] = {
650	0, 0, 0, Vpci3, Vpci4, Vpci5, Vpci6, Vpci7, Vpci8,
651	Vpci9, Vpci10, Vpci11, Vpci12, Vpci13, Vpci14, Vpci15 };
652
653static int
654register_intr __P((int intr, int device_id, unsigned int flags,
655		       inthand2_t *handler, unsigned int* mptr, int unit))
656{
657	if (intr >= 16 || intr <= 2)
658		return (EINVAL);
659	if (pci_int_hdlr [intr])
660		return (EBUSY);
661
662	pci_int_hdlr [intr] = handler;
663	pci_int_unit [intr] = unit;
664	pci_int_mptr [intr] = mptr;
665
666	setidt(NRSVIDT + intr, pci_int_glue[intr], SDT_SYS386IGT, SEL_KPL);
667	return (0);
668}
669#endif /* __FreeBSD2__ */
670#endif /* NPCI */
671