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