pci_cfgreg.c revision 7234
1/**************************************************************************
2**
3**  $Id: pcibus.c,v 1.4 1995/02/26 05:14:51 bde Exp $
4**
5**  pci bus subroutines for i386 architecture.
6**
7**  FreeBSD
8**
9**-------------------------------------------------------------------------
10**
11** Copyright (c) 1994 Wolfgang Stanglmeier.  All rights reserved.
12**
13** Redistribution and use in source and binary forms, with or without
14** modification, are permitted provided that the following conditions
15** are met:
16** 1. Redistributions of source code must retain the above copyright
17**    notice, this list of conditions and the following disclaimer.
18** 2. Redistributions in binary form must reproduce the above copyright
19**    notice, this list of conditions and the following disclaimer in the
20**    documentation and/or other materials provided with the distribution.
21** 3. The name of the author may not be used to endorse or promote products
22**    derived from this software without specific prior written permission.
23**
24** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34**
35***************************************************************************
36*/
37
38#define	__PCIBUS_C___	"pl4 95/03/21"
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/kernel.h>
43
44#include <i386/isa/icu.h>
45#include <i386/isa/isa.h>
46#include <i386/isa/isa_device.h>
47
48#include <pci/pcivar.h>
49#include <pci/pcireg.h>
50#include <pci/pcibus.h>
51
52extern int printf();
53
54#ifdef DENTARO
55
56#define SFAKE (32)
57
58static void
59dec21050 (u_int*reg) {
60	reg[0] = 0x00011011;
61	reg[1]&= 0x000001e7;
62	reg[2] = 0x06040001;
63	reg[3]&= 0x0000f8ff;
64	reg[3]|= 0x000100ff;
65	reg[4] = 0x00000000;
66	reg[5] = 0x00000000;
67	reg[6]&= 0xf8ffffff;
68	reg[7]&= 0x0000f0f0; /* io-limit                       */
69	reg[8]&= 0xfff0fff0; /* mem-limit, non prefatchable    */
70	reg[9]&= 0xfff0fff0; /* mem-limit, prefetchable memory */
71	reg[10] = 0x00000000;
72	reg[11] = 0x00000000;
73	reg[12] = 0x00000000;
74	reg[13] = 0x00000000;
75	reg[14] = 0x00000000;
76	reg[15]&= 0x00ef0000;
77}
78
79static void
80dec21140 (u_int*reg) {
81	reg[0] = 0x00091011u;
82	reg[4]&= 0xfffffffdu;
83	reg[4]|= 0x00000001u;
84	reg[5]&= 0xffffff00u;
85}
86
87struct fake {
88	u_int	tag;
89	void	(*proc)(u_int*);
90};
91
92struct fake faketable [] = {
93{ 0xc70000f1, dec21050 },
94{ 0xc00001f1, dec21140 },
95{ 0xc40001f1, dec21140 },
96{ 0xc80001f1, dec21140 },
97{ 0xcc0001f1, dec21140 },
98};
99
100#define NFAKE (sizeof faketable / sizeof (struct fake))
101
102static u_int fakedata[NFAKE * SFAKE];
103
104u_int* findfake (pcici_t tag)
105{
106	u_int *p;
107	int i;
108	for (i=0; i<NFAKE; i++)
109		if (faketable[i].tag == tag.tag)
110			break;
111
112	if (i>=NFAKE)
113		return (0);
114	p = &fakedata[i*SFAKE];
115	(*faketable[i].proc)(p);
116	return (p);
117}
118#endif /*DENTARO*/
119
120/*-----------------------------------------------------------------
121**
122**	The following functions are provided by the pci bios.
123**	They are used only by the pci configuration.
124**
125**	pcibus_setup():
126**		Probes for a pci system.
127**		Sets pci_maxdevice and pci_mechanism.
128**
129**	pcibus_tag():
130**		Creates a handle for pci configuration space access.
131**		This handle is given to the read/write functions.
132**
133**	pcibus_ftag():
134**		Creates a modified handle.
135**
136**	pcibus_read():
137**		Read a long word from the pci configuration space.
138**		Requires a tag (from pcitag) and the register
139**		number (should be a long word alligned one).
140**
141**	pcibus_write():
142**		Writes a long word to the pci configuration space.
143**		Requires a tag (from pcitag), the register number
144**		(should be a long word alligned one), and a value.
145**
146**	pcibus_regirq():
147**		Register an interupt handler for a pci device.
148**		Requires a tag (from pcitag), the register number
149**		(should be a long word alligned one), and a value.
150**
151**-----------------------------------------------------------------
152*/
153
154static void
155pcibus_setup (void);
156
157static pcici_t
158pcibus_tag (u_char bus, u_char device, u_char func);
159
160static pcici_t
161pcibus_ftag (pcici_t tag, u_char func);
162
163static u_long
164pcibus_read (pcici_t tag, u_long reg);
165
166static void
167pcibus_write (pcici_t tag, u_long reg, u_long data);
168
169static int
170pcibus_ihandler_attach (int irq, void(*ihandler)(), int arg, unsigned* maskp);
171
172static int
173pcibus_ihandler_detach (int irq, void(*handler)());
174
175static int
176pcibus_imask_include (int irq, unsigned* maskptr);
177
178static int
179pcibus_imask_exclude (int irq, unsigned* maskptr);
180
181struct pcibus i386pci = {
182	"pci",
183	pcibus_setup,
184	pcibus_tag,
185	pcibus_ftag,
186	pcibus_read,
187	pcibus_write,
188	ICU_LEN,
189	pcibus_ihandler_attach,
190	pcibus_ihandler_detach,
191	pcibus_imask_include,
192	pcibus_imask_exclude,
193};
194
195/*
196**	Announce structure to generic driver
197*/
198
199DATA_SET (pcibus_set, i386pci);
200
201/*--------------------------------------------------------------------
202**
203**      Determine configuration mode
204**
205**--------------------------------------------------------------------
206*/
207
208
209#define CONF1_ENABLE       0x80000000ul
210#define CONF1_ADDR_PORT    0x0cf8
211#define CONF1_DATA_PORT    0x0cfc
212
213
214#define CONF2_ENABLE_PORT  0x0cf8
215#define CONF2_FORWARD_PORT 0x0cfa
216
217
218static void
219pcibus_setup (void)
220{
221	u_long result, oldval;
222
223	/*---------------------------------------
224	**      Configuration mode 2 ?
225	**---------------------------------------
226	*/
227
228	outb (CONF2_ENABLE_PORT,  0);
229	outb (CONF2_FORWARD_PORT, 0);
230	if (!inb (CONF2_ENABLE_PORT) && !inb (CONF2_FORWARD_PORT)) {
231		pci_mechanism = 2;
232		pci_maxdevice = 16;
233	};
234
235	/*---------------------------------------
236	**      Configuration mode 1 ?
237	**---------------------------------------
238	*/
239
240	oldval = inl (CONF1_ADDR_PORT);
241	outl (CONF1_ADDR_PORT, CONF1_ENABLE);
242	result = inl (CONF1_ADDR_PORT);
243	outl (CONF1_ADDR_PORT, oldval);
244
245	if (result == CONF1_ENABLE) {
246		pci_mechanism = 1;
247		pci_maxdevice = 32;
248	};
249
250	/*---------------------------------------
251	**      No PCI bus available.
252	**---------------------------------------
253	*/
254}
255
256/*--------------------------------------------------------------------
257**
258**      Build a pcitag from bus, device and function number
259**
260**--------------------------------------------------------------------
261*/
262
263static pcici_t
264pcibus_tag (unsigned char bus, unsigned char device, unsigned char func)
265{
266	pcici_t tag;
267
268	tag.cfg1 = 0;
269	if (device >= 32) return tag;
270	if (func   >=  8) return tag;
271
272	switch (pci_mechanism) {
273
274	case 1:
275		tag.cfg1 = CONF1_ENABLE
276			| (((u_long) bus   ) << 16ul)
277			| (((u_long) device) << 11ul)
278			| (((u_long) func  ) <<  8ul);
279		break;
280	case 2:
281		if (device >= 16) break;
282		tag.cfg2.port    = 0xc000 | (device << 8ul);
283		tag.cfg2.enable  = 0xf1 | (func << 1ul);
284		tag.cfg2.forward = bus;
285		break;
286	};
287	return tag;
288}
289
290static pcici_t
291pcibus_ftag (pcici_t tag, u_char func)
292{
293	switch (pci_mechanism) {
294
295	case 1:
296		tag.cfg1 &= ~0x700ul;
297		tag.cfg1 |= (((u_long) func) << 8ul);
298		break;
299	case 2:
300		tag.cfg2.enable  = 0xf1 | (func << 1ul);
301		break;
302	};
303	return tag;
304}
305
306/*--------------------------------------------------------------------
307**
308**      Read register from configuration space.
309**
310**--------------------------------------------------------------------
311*/
312
313static u_long
314pcibus_read (pcici_t tag, u_long reg)
315{
316	u_long addr, data = 0;
317
318#ifdef DENTARO
319	u_int*p = findfake(tag);
320	if (p) {
321#if 0
322		printf ("fake conf_read (tag=%x reg=%d val=%08x).\n",
323			tag.tag, (unsigned) reg, (unsigned) p[reg/4]);
324#endif
325		return (p[reg/4]);
326	}
327#endif
328
329	if (!tag.cfg1) return (0xfffffffful);
330
331	switch (pci_mechanism) {
332
333	case 1:
334		addr = tag.cfg1 | (reg & 0xfc);
335#ifdef PCI_DEBUG
336		printf ("pci_conf_read(1): addr=%x ", addr);
337#endif
338		outl (CONF1_ADDR_PORT, addr);
339		data = inl (CONF1_DATA_PORT);
340		outl (CONF1_ADDR_PORT, 0   );
341		break;
342
343	case 2:
344		addr = tag.cfg2.port | (reg & 0xfc);
345#ifdef PCI_DEBUG
346		printf ("pci_conf_read(2): addr=%x ", addr);
347#endif
348		outb (CONF2_ENABLE_PORT , tag.cfg2.enable );
349		outb (CONF2_FORWARD_PORT, tag.cfg2.forward);
350
351		data = inl ((u_short) addr);
352
353		outb (CONF2_ENABLE_PORT,  0);
354		outb (CONF2_FORWARD_PORT, 0);
355		break;
356	};
357
358#ifdef PCI_DEBUG
359	printf ("data=%x\n", data);
360#endif
361
362	return (data);
363}
364
365/*--------------------------------------------------------------------
366**
367**      Write register into configuration space.
368**
369**--------------------------------------------------------------------
370*/
371
372static void
373pcibus_write (pcici_t tag, u_long reg, u_long data)
374{
375	u_long addr;
376
377#ifdef DENTARO
378	u_int*p = findfake(tag);
379	if (p) {
380#if 0
381		printf ("fake conf_write (tag=%x reg=%d val=%08x).\n",
382			tag.tag, (unsigned) reg, (unsigned) data);
383#endif
384		p[reg/4]=data;
385		return;
386	}
387#endif
388
389	if (!tag.cfg1) return;
390
391	switch (pci_mechanism) {
392
393	case 1:
394		addr = tag.cfg1 | (reg & 0xfc);
395#ifdef PCI_DEBUG
396		printf ("pci_conf_write(1): addr=%x data=%x\n",
397			addr, data);
398#endif
399		outl (CONF1_ADDR_PORT, addr);
400		outl (CONF1_DATA_PORT, data);
401		outl (CONF1_ADDR_PORT,   0 );
402		break;
403
404	case 2:
405		addr = tag.cfg2.port | (reg & 0xfc);
406#ifdef PCI_DEBUG
407		printf ("pci_conf_write(2): addr=%x data=%x\n",
408			addr, data);
409#endif
410		outb (CONF2_ENABLE_PORT,  tag.cfg2.enable);
411		outb (CONF2_FORWARD_PORT, tag.cfg2.forward);
412
413		outl ((u_short) addr, data);
414
415		outb (CONF2_ENABLE_PORT,  0);
416		outb (CONF2_FORWARD_PORT, 0);
417		break;
418	};
419}
420
421/*-----------------------------------------------------------------------
422**
423**	Register an interupt handler for a pci device.
424**
425**-----------------------------------------------------------------------
426*/
427
428static int
429pcibus_ihandler_attach (int irq, void(*func)(), int arg, unsigned * maskptr)
430{
431	int result;
432	result = register_intr(
433		irq,		    /* isa irq	    */
434		0,		    /* deviced??    */
435		0,		    /* flags?	    */
436		(inthand2_t*) func, /* handler	    */
437		maskptr,	    /* mask pointer */
438		arg);		    /* handler arg  */
439
440	if (result) {
441		printf ("@@@ pcibus_ihandler_attach: result=%d\n", result);
442		return (result);
443	};
444	update_intr_masks();
445
446	INTREN ((1ul<<irq));
447	return (0);
448}
449
450static int
451pcibus_ihandler_detach (int irq, void(*func)())
452{
453	int result;
454
455	INTRDIS ((1ul<<irq));
456
457	result = unregister_intr (irq, (inthand2_t*) func);
458
459	if (result)
460		printf ("@@@ pcibus_ihandler_detach: result=%d\n", result);
461
462	update_intr_masks();
463
464	return (result);
465}
466
467static int
468pcibus_imask_include (int irq, unsigned* maskptr)
469{
470	unsigned mask;
471
472	if (!maskptr) return (0);
473
474	mask = 1ul << irq;
475
476	if (*maskptr & mask)
477		return (-1);
478
479	INTRMASK (*maskptr, mask);
480	update_intr_masks();
481
482	return (0);
483}
484
485static int
486pcibus_imask_exclude (int irq, unsigned* maskptr)
487{
488	unsigned mask;
489
490	if (!maskptr) return (0);
491
492	mask = 1ul << irq;
493
494	if (! (*maskptr & mask))
495		return (-1);
496
497	*maskptr &= ~mask;
498	update_intr_masks();
499
500	return (0);
501}
502