pci.c revision 2435
1/**************************************************************************
2**
3**  $Id: pci.c,v 2.0.0.8 94/08/21 19:57:39 wolf 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**  $Log:	pci.c,v $
39**  Revision 2.0.0.8  94/08/21  19:57:39  wolf
40**  Unneeded declarations removed (FreeBSD2.0)
41**
42**  Revision 2.0.0.7  94/08/21  19:25:54  wolf
43**  pci_intr simplified.
44**  new not_supported() function.
45**  Vendor and device ids moved into tables.
46**
47**  Revision 2.0.0.6  94/08/18  22:58:23  wolf
48**  Symbolic names for pci configuration space registers.
49**  last_device: from configuration mode
50**  last_bus: from pcibios.
51**  PCI_MAX_DPI: changed to 4 (settable by config)
52**  interrupt configuration by line or pin
53**
54**  Revision 2.0.0.5  94/08/11  19:04:10  wolf
55**  display of interrupt line configuration register.
56**
57**  Revision 2.0.0.4  94/08/01  20:36:28  wolf
58**  Tiny clean up.
59**
60**  Revision 2.0.0.3  94/08/01  18:52:33  wolf
61**  New vendor entry:  S3.
62**  Scan pci busses #0..#255 as default.
63**  Number of scanned busses and devices settable as option.
64**  Show these numbers before starting the scan.
65**
66**  Revision 2.0.0.2  94/07/27  09:27:19  wolf
67**  New option PCI_QUIET: suppress log messages.
68**
69**  Revision 2.0.0.1  94/07/19  19:06:44  wolf
70**  New vendor entry:  MATROX
71**
72**  Revision 2.0  94/07/10  15:53:29  wolf
73**  FreeBSD release.
74**
75**  Revision 1.0  94/06/07  20:02:19  wolf
76**  Beta release.
77**
78***************************************************************************
79*/
80
81#include <pci.h>
82#if NPCI > 0
83
84/*========================================================
85**
86**	Configuration
87**
88**========================================================
89*/
90
91/*
92**	maximum number of devices which share one interrupt line
93*/
94
95#ifndef PCI_MAX_DPI
96#define PCI_MAX_DPI	(4)
97#endif  /*PCI_MAX_DPI*/
98
99
100/*========================================================
101**
102**	#includes  and  declarations
103**
104**========================================================
105*/
106
107#include <types.h>
108#include <cdefs.h>
109#include <errno.h>
110#include <param.h>
111
112#include <vm/vm.h>
113#include <vm/vm_param.h>
114
115#include <i386/isa/icu.h>
116#include <i386/isa/isa.h>
117#include <i386/isa/isa_device.h>
118
119#include <i386/pci/pci.h>
120#include <i386/pci/pci_device.h>
121#include <i386/pci/pcibios.h>
122
123
124char ident_pci_c[] =
125	"\n$Id: pci.c,v 2.0.0.8 94/08/21 19:57:39 wolf Exp $\n"
126	"Copyright (c) 1994, Wolfgang Stanglmeier\n";
127
128/*
129**	Function prototypes missing in system headers
130*/
131
132extern int printf();
133extern int ffs();
134#if ! (__FreeBSD__ >= 2)
135extern pmap_t pmap_kernel(void);
136#endif
137
138
139/*========================================================
140**
141**	Autoconfiguration (of isa bus)
142**
143**========================================================
144*/
145
146/*
147**      per device (interrupt) data structure.
148*/
149
150static struct {
151	u_short number;
152	u_short isanum;
153	struct {
154		int (*proc)(int dev);
155		dev_t unit;
156	} vector[PCI_MAX_DPI];
157} pcidata [NPCI];
158
159/*
160**	check device ready
161*/
162static int pciprobe (struct isa_device *dev)
163{
164	if (dev->id_unit >= NPCI)
165		return (0);
166
167	if (!pci_conf_mode())
168		return (0);
169
170	return (-1);
171}
172
173/*
174**	initialize the driver structure
175*/
176static int pciattach (struct isa_device *isdp)
177{
178	pcidata[isdp->id_unit].number = 0;
179	pcidata[isdp->id_unit].isanum = ffs(isdp->id_irq)-1;
180	return (1);
181}
182
183/*
184**      ISA driver structure
185*/
186
187struct isa_driver pcidriver = {
188	pciprobe,
189	pciattach,
190	"pci"
191};
192
193/*========================================================
194**
195**	Interrupt forward from isa to pci devices.
196**
197**========================================================
198*/
199
200
201void pciintr (int unit)
202{
203	u_short i;
204	if (unit >= NPCI) return;
205	for (i=0; i<pcidata[unit].number; i++) {
206		(void)(*pcidata[unit].vector[i].proc)(pcidata[unit].vector[i].unit);
207	};
208}
209
210
211/*========================================================
212**
213**	Autoconfiguration of pci devices.
214**
215**	This is reverse to the isa configuration.
216**	(1) find a pci device.
217**	(2) look for a driver.
218**
219**========================================================
220*/
221
222/*--------------------------------------------------------
223**
224**	The pci devices can be mapped to any address.
225**	As default we start at the last gigabyte.
226**
227**--------------------------------------------------------
228*/
229
230#ifndef PCI_PMEM_START
231#define PCI_PMEM_START 0xc0000000
232#endif
233
234static vm_offset_t pci_paddr = PCI_PMEM_START;
235
236/*---------------------------------------------------------
237**
238**	pci_configure ()
239**
240**---------------------------------------------------------
241*/
242
243static void not_supported (pcici_t tag, u_long type);
244
245void pci_configure()
246{
247	u_char	device,last_device;
248	u_short	bus,last_bus;
249	pcici_t	tag;
250	pcidi_t type;
251	u_long	data;
252	int	unit;
253	int	intpin;
254	int	isanum;
255	int	pci_mode;
256
257	struct pci_driver *drp;
258	struct pci_device *dvp;
259
260	/*
261	**	check pci bus present
262	*/
263
264	pci_mode = pci_conf_mode ();
265	if (!pci_mode) return;
266	last_bus = pci_last_bus ();
267	last_device = pci_mode==1 ? 31 : 15;
268
269	/*
270	**	hello world ..
271	*/
272
273#ifndef PCI_QUIET
274	printf ("PCI configuration mode %d.\n", pci_mode);
275	printf ("Scanning device 0..%d on pci bus 0..%d "
276		"($Revision: 2.0.0.8 $)\n",
277		last_device, last_bus);
278#endif
279
280	for (bus=0;bus<=last_bus; bus++)
281	    for (device=0; device<=last_device; device ++) {
282		tag = pcitag (bus, device, 0);
283		type = pci_conf_read (tag, PCI_ID_REG);
284
285		if ((!type) || (type==0xfffffffful)) continue;
286
287		/*
288		**	lookup device in ioconfiguration:
289		*/
290
291		for (dvp = pci_devtab; drp=dvp->pd_driver; dvp++) {
292			if (drp->device_id == type) break;
293		};
294
295#ifdef PCI_QUIET
296		if (!drp) continue;
297#endif
298		printf ("on pci%d:%d ", bus, device);
299#ifndef PCI_QUIET
300		if (!drp) {
301			not_supported (tag, type);
302			continue;
303		};
304#endif
305
306		/*
307		**	found it.
308		**	probe returns the device unit.
309		*/
310
311		printf ("<%s>", drp -> vendor);
312
313		unit = (*drp->probe) (tag);
314
315		if (unit<0) {
316			printf (" probe failed.\n");
317			continue;
318		};
319
320		/*
321		**	install interrupts
322		*/
323
324		data = pci_conf_read (tag, PCI_INTERRUPT_REG);
325		intpin = PCI_INTERRUPT_PIN_EXTRACT(data);
326		if (intpin) {
327			int idx=NPCI;
328
329			/*
330			**  Usage of int line register (if set by bios)
331			**  Matt Thomas	<thomas@lkg.dec.com>
332			*/
333
334			isanum = PCI_INTERRUPT_LINE_EXTRACT(data);
335			if (isanum) {
336				printf (" il=%d", isanum);
337				for (idx = 0; idx < NPCI; idx++) {
338					if (pcidata[idx].isanum == isanum)
339						break;
340				};
341			};
342
343			/*
344			**	Or believe to the interrupt pin register.
345			*/
346
347			if (idx >= NPCI) idx = intpin-1;
348
349			/*
350			**	And install the interrupt.
351			*/
352
353			if (idx<NPCI) {
354				u_short entry = pcidata[idx].number;
355				printf (" irq %c", 0x60+intpin);
356				if (entry < PCI_MAX_DPI) {
357					pcidata[idx].vector[entry].proc = drp->intr;
358					pcidata[idx].vector[entry].unit = unit;
359					entry++;
360				};
361				printf (" isa=%d [%d]",pcidata[idx].isanum, entry);
362				pcidata[idx].number=entry;
363			} else {
364				printf (" not installed");
365			};
366		};
367
368		/*
369		**	enable memory access
370		*/
371		data = pci_conf_read (tag, PCI_COMMAND_STATUS_REG)
372			& 0xffff | PCI_COMMAND_MEM_ENABLE;
373		pci_conf_write (tag, (u_char) PCI_COMMAND_STATUS_REG, data);
374
375		/*
376		**	attach device
377		**	may produce additional log messages,
378		**	i.e. when installing subdevices.
379		*/
380
381		printf (" as %s%d\n", drp->name,unit);
382		(void) (*drp->attach) (tag);
383
384	};
385
386	printf ("pci uses physical addresses from %x to %x\n",
387			PCI_PMEM_START, pci_paddr);
388}
389
390/*-----------------------------------------------------------------------
391**
392**	Map device into port space.
393**
394**	PCI-Specification:  6.2.5.1: address maps
395**
396**-----------------------------------------------------------------------
397*/
398
399extern vm_map_t kernel_map;
400
401int pci_map_port (pcici_t tag, u_long reg, u_short* pa)
402{
403	/*
404	**	@MAPIO@ not yet implemented.
405	*/
406	return (ENOSYS);
407}
408
409/*-----------------------------------------------------------------------
410**
411**	Map device into virtual and physical space
412**
413**	PCI-Specification:  6.2.5.1: address maps
414**
415**-----------------------------------------------------------------------
416*/
417
418int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa)
419{
420	u_long data, result;
421	vm_size_t vsize;
422	vm_offset_t vaddr;
423
424	/*
425	**	sanity check
426	*/
427
428	if (reg <= PCI_MAP_REG_START || reg >= PCI_MAP_REG_END || (reg & 3))
429		return (EINVAL);
430
431	/*
432	**	get size and type of memory
433	**
434	**	type is in the lowest four bits.
435	**	If device requires 2^n bytes, the next
436	**	n-4 bits are read as 0.
437	*/
438
439	pci_conf_write (tag, reg, 0xfffffffful);
440	data = pci_conf_read (tag, reg);
441
442	switch (data & 0x0f) {
443
444	case PCI_MAP_MEMORY_TYPE_32BIT:	/* 32 bit non cachable */
445		break;
446
447	default:	/* unknown */
448		return (EINVAL);
449	};
450
451	/*
452	**	mask out the type,
453	**	and round up to a page size
454	*/
455
456	vsize = round_page (-(data &  PCI_MAP_MEMORY_ADDRESS_MASK));
457
458	printf ("          memory size=0x%x", vsize);
459
460	if (!vsize) return (EINVAL);
461
462	/*
463	**	try to map device to virtual space
464	*/
465
466	vaddr  = vm_map_min (kernel_map);
467
468	result = vm_map_find (kernel_map, (void*)0, (vm_offset_t) 0,
469				&vaddr, vsize, TRUE);
470
471	if (result != KERN_SUCCESS) {
472		printf (" vm_map_find failed(%d)\n", result);
473		return (ENOMEM);
474	};
475
476	/*
477	**	align physical address to virtual size
478	*/
479
480	if (data = pci_paddr % vsize)
481		pci_paddr += vsize - data;
482
483	/*
484	**	display values.
485	*/
486
487	printf (" virtual=0x%x physical=0x%x\n", vaddr, pci_paddr);
488
489	/*
490	**	return them to the driver
491	*/
492
493	*va = vaddr;
494	*pa = pci_paddr;
495
496	/*
497	**	set device address
498	*/
499
500	pci_conf_write (tag, reg, pci_paddr);
501
502	/*
503	**	map physical
504	*/
505
506	while (vsize >= NBPG) {
507		pmap_enter (pmap_kernel(), vaddr, pci_paddr,
508				VM_PROT_READ|VM_PROT_WRITE, TRUE);
509		vaddr     += NBPG;
510		pci_paddr += NBPG;
511		vsize     -= NBPG;
512	};
513
514	return (0);
515}
516
517struct vt {
518	u_short	ident;
519	char*	name;
520};
521
522struct dt {
523	u_long	ident;
524	char*	name;
525};
526
527static struct vt VendorTable[] = {
528	{0x1002, "ATI TECHNOLOGIES INC"},
529	{0x1011, "DIGITAL EQUIPMENT COMPANY"},
530	{0x101A, "NCR"},
531	{0x102B, "MATROX"},
532	{0x1045, "OPTI"},
533	{0x5333, "S3 INC."},
534	{0x8086, "INTEL CORPORATION"},
535	{0,0}
536};
537
538static struct dt DeviceTable[] = {
539	{0x04848086, " 82378IB pci-isa bridge"},
540	{0x04838086, " 82424ZX cache dram controller"},
541	{0x04828086, " 82375EB pci-eisa bridge"},
542	{0x04A38086, " 82434LX pci cache memory controller"},
543	{0,0}
544};
545
546void not_supported (pcici_t tag, u_long type)
547{
548	u_char	reg;
549	u_long	data;
550	struct vt * vp;
551	struct dt * dp;
552
553	/*
554	**	lookup the names.
555	*/
556
557	for (vp=VendorTable; vp->ident; vp++)
558		if (vp->ident == (type & 0xffff))
559			break;
560
561	for (dp=DeviceTable; dp->ident; dp++)
562		if (dp->ident == type)
563			break;
564
565	/*
566	**	and display them.
567	*/
568
569	if (vp->ident) printf (vp->name);
570		else   printf ("vendor=%x", type & 0xffff);
571
572	if (dp->ident) printf (dp->name);
573		else   printf (", device=%x", type >> 16);
574
575	printf (" [not supported]\n");
576
577	for (reg=PCI_MAP_REG_START; reg<PCI_MAP_REG_END; reg+=4) {
578		data = pci_conf_read (tag, reg);
579		if (!data) continue;
580		switch (data&7) {
581
582		case 1:
583		case 5:
584			printf ("	map(%x): io(%x)\n", reg, data & ~3);
585			break;
586		case 0:
587			printf ("	map(%x): mem32(%x)\n", reg, data & ~7);
588			break;
589		case 2:
590			printf ("	map(%x): mem20(%x)\n", reg, data & ~7);
591			break;
592		case 4:
593			printf ("	map(%x): mem64(%x)\n", reg, data & ~7);
594			break;
595		};
596	};
597}
598#endif
599