pci.c revision 6131
1/**************************************************************************
2**
3**  $Id: pci.c,v 1.9 1994/11/02 23:47:13 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 <pci/pcireg.h>
67
68#ifdef __FreeBSD2__
69#include <sys/devconf.h>
70
71struct pci_devconf {
72	struct kern_devconf pdc_kdc;
73	struct pci_info     pdc_pi;
74};
75#endif
76
77/*
78**	Function prototypes missing in system headers
79*/
80
81#ifndef __FreeBSD2__
82extern	pmap_t pmap_kernel(void);
83static	vm_offset_t pmap_mapdev (vm_offset_t paddr, vm_size_t vsize);
84
85/*
86 * Type of the first (asm) part of an interrupt handler.
87 */
88typedef void inthand_t __P((u_int cs, u_int ef, u_int esp, u_int ss));
89
90/*
91 * Usual type of the second (C) part of an interrupt handler.  Some bogus
92 * ones need the arg to be the interrupt frame (and not a copy of it, which
93 * is all that is possible in C).
94 */
95typedef void inthand2_t __P((int unit));
96
97/*
98**	XXX	@FreeBSD2@
99**
100**	Unfortunately, the mptr argument is _no_ pointer in 2.0 FreeBSD.
101**	We would prefer a pointer because it enables us to install
102**	new interrupt handlers at any time.
103**	(This is just going to be changed ... <se> :)
104**	In 2.0 FreeBSD later installed interrupt handlers may change
105**	the xyz_imask, but this would not be recognized by handlers
106**	which are installed before.
107*/
108
109static int
110register_intr __P((int intr, int device_id, unsigned int flags,
111		       inthand2_t *handler, unsigned int * mptr, int unit));
112extern unsigned intr_mask[ICU_LEN];
113
114#endif /* !__FreeBSD2__ */
115
116/*========================================================
117**
118**	Autoconfiguration of pci devices.
119**
120**	This is reverse to the isa configuration.
121**	(1) find a pci device.
122**	(2) look for a driver.
123**
124**========================================================
125*/
126
127/*--------------------------------------------------------
128**
129**	The pci devices can be mapped to any address.
130**	As default we start at the last gigabyte.
131**
132**--------------------------------------------------------
133*/
134
135#ifndef PCI_PMEM_START
136#define PCI_PMEM_START 0xc0000000
137#endif
138
139static	vm_offset_t pci_paddr = PCI_PMEM_START;
140
141/*--------------------------------------------------------
142**
143**	The pci device interrupt lines should have been
144**	assigned by the bios. But if the bios failed to
145**	to it, we set it.
146**
147**--------------------------------------------------------
148*/
149
150#ifndef PCI_IRQ
151#define PCI_IRQ 0
152#endif
153
154static	u_long      pci_irq   = PCI_IRQ;
155
156/*---------------------------------------------------------
157**
158**	pci_configure ()
159**
160**	Probe all devices on pci bus and attach them.
161**
162**	May be called more than once.
163**	Any device is attached only once.
164**	(Attached devices are remembered in pci_seen.)
165**
166**---------------------------------------------------------
167*/
168
169static void not_supported (pcici_t tag, u_long type);
170
171static unsigned long pci_seen[NPCI];
172
173static int pci_conf_count;
174
175#ifdef __FreeBSD2__
176static int
177pci_externalize (struct proc *, struct kern_devconf *, void *, size_t);
178
179static int
180pci_internalize (struct proc *, struct kern_devconf *, void *, size_t);
181
182#endif /* __FreeBSD2__ */
183
184void pci_configure()
185{
186	u_char	device,last_device;
187	u_short	bus;
188	pcici_t	tag;
189	pcidi_t type;
190	u_long	data;
191	int	unit;
192	int	pci_mechanism;
193	int	pciint;
194	int	irq;
195	char*	name=0;
196	vm_offset_t old_addr=pci_paddr;
197
198	struct pci_driver *drp=0;
199	struct pci_device *dvp;
200
201#ifdef __FreeBSD2__
202	struct pci_devconf *pdcp;
203#endif
204
205	/*
206	**	check pci bus present
207	*/
208
209	pci_mechanism = pci_conf_mode ();
210	if (!pci_mechanism) return;
211	last_device = pci_mechanism==1 ? 31 : 15;
212
213	/*
214	**	hello world ..
215	*/
216
217
218	for (bus=0;bus<NPCI;bus++) {
219#ifndef PCI_QUIET
220	    printf ("pci%d: scanning device 0..%d, mechanism=%d.\n",
221		bus, last_device, pci_mechanism);
222#endif
223	    for (device=0; device<=last_device; device ++) {
224
225		if (pci_seen[bus] & (1ul << device))
226			continue;
227
228		tag = pcitag (bus, device, 0);
229		type = pci_conf_read (tag, PCI_ID_REG);
230
231		if ((!type) || (type==0xfffffffful)) continue;
232
233		/*
234		**	lookup device in ioconfiguration:
235		*/
236
237		for (dvp = pci_devtab; dvp->pd_name; dvp++) {
238			drp = dvp->pd_driver;
239			if (!drp)
240				continue;
241			if ((name=(*drp->probe)(tag, type)))
242				break;
243		};
244
245		if (!dvp->pd_name) {
246#ifndef PCI_QUIET
247			if (pci_conf_count)
248				continue;
249			printf("pci%d:%d: ", bus, device);
250			not_supported (tag, type);
251#endif
252			continue;
253		};
254
255		pci_seen[bus] |= (1ul << device);
256		/*
257		**	Get and increment the unit.
258		*/
259
260		unit = (*drp->count)++;
261
262		/*
263		**	ignore device ?
264		*/
265
266		if (!*name) continue;
267
268		/*
269		**	Announce this device
270		*/
271
272		printf ("%s%d <%s>", dvp->pd_name, unit, name);
273
274		/*
275		**	Get the int pin number (pci interrupt number a-d)
276		**	from the pci configuration space.
277		*/
278
279		data = pci_conf_read (tag, PCI_INTERRUPT_REG);
280		pciint = PCI_INTERRUPT_PIN_EXTRACT(data);
281
282		if (pciint) {
283
284			printf (" int %c", 0x60+pciint);
285
286			/*
287			**	If the interrupt line register is not set,
288			**	set it now from PCI_IRQ.
289			*/
290
291			if (!(PCI_INTERRUPT_LINE_EXTRACT(data))) {
292
293				irq = pci_irq & 0x0f;
294				pci_irq >>= 4;
295
296				data = PCI_INTERRUPT_LINE_INSERT(data, irq);
297				printf (" (config)");
298				pci_conf_write (tag, PCI_INTERRUPT_REG, data);
299			};
300
301			irq = PCI_INTERRUPT_LINE_EXTRACT(data);
302
303			/*
304			**	If it's zero, the isa irq number is unknown,
305			**	and we cannot bind the pci interrupt to isa.
306			*/
307
308			if (irq)
309				printf (" irq %d", irq);
310			else
311				printf (" not bound");
312		};
313
314		/*
315		**	enable memory access
316		*/
317
318		data = (pci_conf_read (tag, PCI_COMMAND_STATUS_REG)
319			& 0xffff) | PCI_COMMAND_MEM_ENABLE;
320
321		pci_conf_write (tag, (u_char) PCI_COMMAND_STATUS_REG, data);
322
323		/*
324		**	show pci slot.
325		*/
326
327		printf (" on pci%d:%d\n", bus, device);
328
329#ifdef __FreeBSD2__
330
331		/*
332		**	Allocate a devconf structure
333		*/
334
335		pdcp = (struct pci_devconf *)
336                	malloc (sizeof (struct pci_devconf),M_DEVBUF,M_WAITOK);
337
338		/*
339		**	Fill in.
340		**
341		**	Sorry, this is not yet complete.
342		**	We should, and eventually will, set the
343		**	parent pointer to a pci bus devconf structure,
344		**	and arrange to set the state field dynamically.
345		**
346		**	But I'll go to vacation today, and after all,
347		**	wasn't there a new feature freeze on Oct 1.?
348		*/
349
350		pdcp -> pdc_pi.pi_bus	 = bus;
351		pdcp -> pdc_pi.pi_device = device;
352
353		pdcp -> pdc_kdc.kdc_name = dvp->pd_name;
354		pdcp -> pdc_kdc.kdc_unit = unit;
355
356		pdcp -> pdc_kdc.kdc_md.mddc_devtype = MDDT_PCI;
357
358		pdcp -> pdc_kdc.kdc_externalize = pci_externalize;
359		pdcp -> pdc_kdc.kdc_internalize = pci_internalize;
360
361		pdcp -> pdc_kdc.kdc_datalen     = PCI_EXTERNAL_LEN;
362		pdcp -> pdc_kdc.kdc_parentdata  = &pdcp->pdc_pi;
363		pdcp -> pdc_kdc.kdc_state       = DC_UNKNOWN;
364		pdcp -> pdc_kdc.kdc_description = name;
365
366		/*
367		**	And register this device
368		*/
369
370		dev_attach (&pdcp->pdc_kdc);
371
372#endif /* __FreeBSD2__ */
373
374
375		/*
376		**	attach device
377		**	may produce additional log messages,
378		**	i.e. when installing subdevices.
379		*/
380
381		(*drp->attach) (tag, unit);
382	    };
383	};
384
385#ifndef PCI_QUIET
386	if (pci_paddr != old_addr)
387		printf ("pci uses physical addresses from 0x%lx to 0x%lx\n",
388			(u_long)PCI_PMEM_START, (u_long)pci_paddr);
389#endif
390	pci_conf_count++;
391}
392
393/*-----------------------------------------------------------------------
394**
395**	Map device into port space.
396**
397**	PCI-Specification:  6.2.5.1: address maps
398**
399**-----------------------------------------------------------------------
400*/
401
402int pci_map_port (pcici_t tag, u_long reg, u_short* pa)
403{
404	/*
405	**	@MAPIO@ not yet implemented.
406	*/
407	printf ("pci_map_port failed: not yet implemented\n");
408	return (0);
409}
410
411/*-----------------------------------------------------------------------
412**
413**	Map device into virtual and physical space
414**
415**	PCI-Specification:  6.2.5.1: address maps
416**
417**-----------------------------------------------------------------------
418*/
419
420int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa)
421{
422	u_long data;
423	vm_size_t vsize;
424	vm_offset_t vaddr;
425
426	/*
427	**	sanity check
428	*/
429
430        if (reg < PCI_MAP_REG_START || reg >= PCI_MAP_REG_END || (reg & 3)) {
431        	printf ("pci_map_mem failed: bad register=0x%x\n",
432               		(unsigned)reg);
433                return (0);
434	};
435
436	/*
437	**	get size and type of memory
438	**
439	**	type is in the lowest four bits.
440	**	If device requires 2^n bytes, the next
441	**	n-4 bits are read as 0.
442	*/
443
444	pci_conf_write (tag, reg, 0xfffffffful);
445	data = pci_conf_read (tag, reg);
446
447	switch (data & 0x0f) {
448
449	case PCI_MAP_MEMORY_TYPE_32BIT:	/* 32 bit non cachable */
450		break;
451
452	default:	/* unknown */
453                printf ("pci_map_mem failed: bad memory type=0x%x\n",
454               		(unsigned) data);
455                return (0);
456	};
457
458	/*
459	**	mask out the type,
460	**	and round up to a page size
461	*/
462
463	vsize = round_page (-(data &  PCI_MAP_MEMORY_ADDRESS_MASK));
464
465	if (!vsize) return (0);
466
467	/*
468	**	align physical address to virtual size
469	*/
470
471	if ((data = pci_paddr % vsize))
472		pci_paddr += vsize - data;
473
474	vaddr = (vm_offset_t) pmap_mapdev (pci_paddr, vsize);
475
476
477	if (!vaddr) return (0);
478
479#ifndef PCI_QUIET
480	/*
481	**	display values.
482	*/
483
484	printf ("\treg%d: virtual=0x%lx physical=0x%lx\n",
485		(unsigned) reg, (u_long)vaddr, (u_long)pci_paddr);
486#endif
487
488	/*
489	**	return them to the driver
490	*/
491
492	*va = vaddr;
493	*pa = pci_paddr;
494
495	/*
496	**	set device address
497	*/
498
499	pci_conf_write (tag, reg, pci_paddr);
500
501	/*
502	**	and don't forget to increment pci_paddr
503	*/
504
505	pci_paddr += vsize;
506
507	return (1);
508}
509
510/*------------------------------------------------------------
511**
512**	Interface functions for the devconf module.
513**
514**------------------------------------------------------------
515*/
516
517static int
518pci_externalize (struct proc *p, struct kern_devconf *kdcp, void *u, size_t l)
519{
520	struct pci_externalize_buffer buffer;
521	struct pci_info * pip = kdcp->kdc_parentdata;
522        pcici_t tag;
523	int	i;
524
525	if (l < sizeof buffer) {
526                return ENOMEM;
527	};
528
529	tag = pcitag (pip->pi_bus, pip->pi_device, 0);
530
531	buffer.peb_pci_info	= *pip;
532
533	for (i=0; i<PCI_EXT_CONF_LEN; i++) {
534		buffer.peb_config[i] = pci_conf_read (tag, i*4);
535	};
536
537        return copyout(&buffer, u, sizeof buffer);
538}
539
540
541static int
542pci_internalize (struct proc *p, struct kern_devconf *kdcp, void *u, size_t s)
543{
544        return EOPNOTSUPP;
545}
546
547/*-----------------------------------------------------------------------
548**
549**	Map pci interrupts to isa interrupts.
550**
551**-----------------------------------------------------------------------
552*/
553
554static	unsigned int	pci_int_mask [16];
555
556int pci_map_int (pcici_t tag, int(*func)(), void* arg, unsigned* maskptr)
557{
558	int irq;
559	unsigned mask;
560
561	irq = PCI_INTERRUPT_LINE_EXTRACT(
562		pci_conf_read (tag, PCI_INTERRUPT_REG));
563
564	if (irq >= 16 || irq <= 0) {
565		printf ("pci_map_int failed: no int line set.\n");
566		return (0);
567	}
568
569	mask = 1ul << irq;
570
571	if (!maskptr)
572		maskptr = &pci_int_mask[irq];
573
574	INTRMASK (*maskptr, mask);
575
576	register_intr(
577		irq,		/* isa irq	*/
578		0,		/* deviced??	*/
579		0,		/* flags?	*/
580		(inthand2_t*) func, /* handler	*/
581		maskptr,	/* mask pointer	*/
582		(int) arg);	/* handler arg	*/
583
584#ifdef __FreeBSD2__
585	/*
586	**	XXX See comment at beginning of file.
587	**
588	**	Have to update all the interrupt masks ... Grrrrr!!!
589	*/
590	{
591		unsigned * mp = &intr_mask[0];
592		/*
593		**	update the isa interrupt masks.
594		*/
595		for (mp=&intr_mask[0]; mp<&intr_mask[ICU_LEN]; mp++)
596			if (*mp & *maskptr)
597				*mp |= mask;
598		/*
599		**	update the pci interrupt masks.
600		*/
601		for (mp=&pci_int_mask[0]; mp<&pci_int_mask[16]; mp++)
602			if (*mp & *maskptr)
603				*mp |= mask;
604	};
605#endif
606
607	INTREN (mask);
608
609	return (1);
610}
611
612/*-----------------------------------------------------------
613**
614**	Display of unknown devices.
615**
616**-----------------------------------------------------------
617*/
618struct vt {
619	u_short	ident;
620	char*	name;
621};
622
623static struct vt VendorTable[] = {
624	{0x1002, "ATI TECHNOLOGIES INC"},
625	{0x1011, "DIGITAL EQUIPMENT CORPORATION"},
626	{0x101A, "NCR"},
627	{0x102B, "MATROX"},
628	{0x1045, "OPTI"},
629	{0x5333, "S3 INC."},
630	{0x8086, "INTEL CORPORATION"},
631	{0,0}
632};
633
634static const char *const majclasses[] = {
635	"old", "storage", "network", "display",
636	"multimedia", "memory", "bridge"
637};
638
639void not_supported (pcici_t tag, u_long type)
640{
641	u_char	reg;
642	u_long	data;
643	struct vt * vp;
644
645	/*
646	**	lookup the names.
647	*/
648
649	for (vp=VendorTable; vp->ident; vp++)
650		if (vp->ident == (type & 0xffff))
651			break;
652
653	/*
654	**	and display them.
655	*/
656
657	if (vp->ident) printf (vp->name);
658		else   printf ("vendor=0x%lx", type & 0xffff);
659
660	printf (", device=0x%lx", type >> 16);
661
662	data = (pci_conf_read(tag, PCI_CLASS_REG) >> 24) & 0xff;
663	if (data < sizeof(majclasses) / sizeof(majclasses[0]))
664		printf(", class=%s", majclasses[data]);
665
666	printf (" [not supported]\n");
667
668	for (reg=PCI_MAP_REG_START; reg<PCI_MAP_REG_END; reg+=4) {
669		data = pci_conf_read (tag, reg);
670		if (!data) continue;
671		switch (data&7) {
672
673		case 1:
674		case 5:
675			printf ("	map(%x): io(%lx)\n",
676				reg, data & ~3);
677			break;
678		case 0:
679			printf ("	map(%x): mem32(%lx)\n",
680				reg, data & ~7);
681			break;
682		case 2:
683			printf ("	map(%x): mem20(%lx)\n",
684				reg, data & ~7);
685			break;
686		case 4:
687			printf ("	map(%x): mem64(%lx)\n",
688				reg, data & ~7);
689			break;
690		}
691	}
692}
693
694#ifndef __FreeBSD2__
695/*-----------------------------------------------------------
696**
697**	Mapping of physical to virtual memory
698**
699**-----------------------------------------------------------
700*/
701
702extern vm_map_t kernel_map;
703
704static	vm_offset_t pmap_mapdev (vm_offset_t paddr, vm_size_t vsize)
705{
706	vm_offset_t	vaddr,value;
707	u_long		result;
708
709	vaddr  = vm_map_min (kernel_map);
710
711	result = vm_map_find (kernel_map, (void*)0, (vm_offset_t) 0,
712				&vaddr, vsize, TRUE);
713
714	if (result != KERN_SUCCESS) {
715		printf (" vm_map_find failed(%d)\n", result);
716		return (0);
717	};
718
719	/*
720	**	map physical
721	*/
722
723	value = vaddr;
724	while (vsize >= NBPG) {
725		pmap_enter (pmap_kernel(), vaddr, paddr,
726				VM_PROT_READ|VM_PROT_WRITE, TRUE);
727		vaddr += NBPG;
728		paddr += NBPG;
729		vsize -= NBPG;
730	};
731	return (value);
732}
733
734/*------------------------------------------------------------
735**
736**	Emulate the register_intr() function of FreeBSD 2.0
737**
738**	requires a patch:
739**	FreeBSD 2.0:	"/sys/i386/isa/vector.s"
740**	386bsd0.1:	"/sys/i386/isa/icu.s"
741**	386bsd1.0:	Please ask Jesus Monroy Jr.
742**
743**------------------------------------------------------------
744*/
745
746#include <machine/segments.h>
747
748int		pci_int_unit [16];
749inthand2_t*    (pci_int_hdlr [16]);
750unsigned int *	pci_int_mptr [16];
751unsigned int	pci_int_count[16];
752
753extern void
754	Vpci3(), Vpci4(), Vpci5(), Vpci6(), Vpci7(), Vpci8(), Vpci9(),
755	Vpci10(), Vpci11(), Vpci12(), Vpci13(), Vpci14(), Vpci15();
756
757static inthand_t* pci_int_glue[16] = {
758	0, 0, 0, Vpci3, Vpci4, Vpci5, Vpci6, Vpci7, Vpci8,
759	Vpci9, Vpci10, Vpci11, Vpci12, Vpci13, Vpci14, Vpci15 };
760
761static int
762register_intr __P((int intr, int device_id, unsigned int flags,
763		       inthand2_t *handler, unsigned int* mptr, int unit))
764{
765	if (intr >= 16 || intr <= 2)
766		return (EINVAL);
767	if (pci_int_hdlr [intr])
768		return (EBUSY);
769
770	pci_int_hdlr [intr] = handler;
771	pci_int_unit [intr] = unit;
772	pci_int_mptr [intr] = mptr;
773
774	setidt(NRSVIDT + intr, pci_int_glue[intr], SDT_SYS386IGT, SEL_KPL);
775	return (0);
776}
777#endif /* __FreeBSD2__ */
778#endif /* NPCI */
779