pci_cfgreg.c revision 9379
1/**************************************************************************
2**
3**  $Id: pcibus.c,v 1.9 1995/06/28 15:54:57 se 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
52/*-----------------------------------------------------------------
53**
54**	The following functions are provided by the pci bios.
55**	They are used only by the pci configuration.
56**
57**	pcibus_setup():
58**		Probes for a pci system.
59**		Sets pci_maxdevice and pci_mechanism.
60**
61**	pcibus_tag():
62**		Creates a handle for pci configuration space access.
63**		This handle is given to the read/write functions.
64**
65**	pcibus_ftag():
66**		Creates a modified handle.
67**
68**	pcibus_read():
69**		Read a long word from the pci configuration space.
70**		Requires a tag (from pcitag) and the register
71**		number (should be a long word alligned one).
72**
73**	pcibus_write():
74**		Writes a long word to the pci configuration space.
75**		Requires a tag (from pcitag), the register number
76**		(should be a long word alligned one), and a value.
77**
78**	pcibus_regirq():
79**		Register an interupt handler for a pci device.
80**		Requires a tag (from pcitag), the register number
81**		(should be a long word alligned one), and a value.
82**
83**-----------------------------------------------------------------
84*/
85
86static void
87pcibus_setup (void);
88
89static pcici_t
90pcibus_tag (u_char bus, u_char device, u_char func);
91
92static pcici_t
93pcibus_ftag (pcici_t tag, u_char func);
94
95static u_long
96pcibus_read (pcici_t tag, u_long reg);
97
98static void
99pcibus_write (pcici_t tag, u_long reg, u_long data);
100
101static int
102pcibus_ihandler_attach (int irq, void(*ihandler)(), int arg, unsigned* maskp);
103
104static int
105pcibus_ihandler_detach (int irq, void(*handler)());
106
107static int
108pcibus_imask_include (int irq, unsigned* maskptr);
109
110static int
111pcibus_imask_exclude (int irq, unsigned* maskptr);
112
113struct pcibus i386pci = {
114	"pci",
115	pcibus_setup,
116	pcibus_tag,
117	pcibus_ftag,
118	pcibus_read,
119	pcibus_write,
120	ICU_LEN,
121	pcibus_ihandler_attach,
122	pcibus_ihandler_detach,
123	pcibus_imask_include,
124	pcibus_imask_exclude,
125};
126
127/*
128**	Announce structure to generic driver
129*/
130
131DATA_SET (pcibus_set, i386pci);
132
133/*--------------------------------------------------------------------
134**
135**      Determine configuration mode
136**
137**--------------------------------------------------------------------
138*/
139
140
141#define CONF1_ENABLE       0x80000000ul
142#define CONF1_ENABLE_CHK   0xF0000000ul
143#define CONF1_ADDR_PORT    0x0cf8
144#define CONF1_DATA_PORT    0x0cfc
145
146
147#define CONF2_ENABLE_PORT  0x0cf8
148#define CONF2_FORWARD_PORT 0x0cfa
149
150
151static void
152pcibus_setup (void)
153{
154	u_long result, oldval;
155
156	/*---------------------------------------
157	**      Configuration mode 1 ?
158	**---------------------------------------
159	*/
160
161	oldval = inl (CONF1_ADDR_PORT);
162	outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
163	outb (CONF1_ADDR_PORT +3, 0);
164	result = inl (CONF1_ADDR_PORT);
165	outl (CONF1_ADDR_PORT, oldval);
166
167	if (result & CONF1_ENABLE) {
168		pci_mechanism = 1;
169		pci_maxdevice = 32;
170		return;
171	};
172
173	/*---------------------------------------
174	**      Configuration mode 2 ?
175	**---------------------------------------
176	*/
177
178	outb (CONF2_ENABLE_PORT,  0);
179	outb (CONF2_FORWARD_PORT, 0);
180	if (!inb (CONF2_ENABLE_PORT) && !inb (CONF2_FORWARD_PORT)) {
181		pci_mechanism = 2;
182		pci_maxdevice = 16;
183		return;
184	};
185
186	/*---------------------------------------
187	**      No PCI bus available.
188	**---------------------------------------
189	*/
190}
191
192/*--------------------------------------------------------------------
193**
194**      Build a pcitag from bus, device and function number
195**
196**--------------------------------------------------------------------
197*/
198
199static pcici_t
200pcibus_tag (unsigned char bus, unsigned char device, unsigned char func)
201{
202	pcici_t tag;
203
204	tag.cfg1 = 0;
205	if (device >= 32) return tag;
206	if (func   >=  8) return tag;
207
208	switch (pci_mechanism) {
209
210	case 1:
211		tag.cfg1 = CONF1_ENABLE
212			| (((u_long) bus   ) << 16ul)
213			| (((u_long) device) << 11ul)
214			| (((u_long) func  ) <<  8ul);
215		break;
216	case 2:
217		if (device >= 16) break;
218		tag.cfg2.port    = 0xc000 | (device << 8ul);
219		tag.cfg2.enable  = 0xf1 | (func << 1ul);
220		tag.cfg2.forward = bus;
221		break;
222	};
223	return tag;
224}
225
226static pcici_t
227pcibus_ftag (pcici_t tag, u_char func)
228{
229	switch (pci_mechanism) {
230
231	case 1:
232		tag.cfg1 &= ~0x700ul;
233		tag.cfg1 |= (((u_long) func) << 8ul);
234		break;
235	case 2:
236		tag.cfg2.enable  = 0xf1 | (func << 1ul);
237		break;
238	};
239	return tag;
240}
241
242/*--------------------------------------------------------------------
243**
244**      Read register from configuration space.
245**
246**--------------------------------------------------------------------
247*/
248
249static u_long
250pcibus_read (pcici_t tag, u_long reg)
251{
252	u_long addr, data = 0;
253
254	if (!tag.cfg1) return (0xfffffffful);
255
256	switch (pci_mechanism) {
257
258	case 1:
259		addr = tag.cfg1 | (reg & 0xfc);
260#ifdef PCI_DEBUG
261		printf ("pci_conf_read(1): addr=%x ", addr);
262#endif
263		outl (CONF1_ADDR_PORT, addr);
264		data = inl (CONF1_DATA_PORT);
265		outl (CONF1_ADDR_PORT, 0   );
266		break;
267
268	case 2:
269		addr = tag.cfg2.port | (reg & 0xfc);
270#ifdef PCI_DEBUG
271		printf ("pci_conf_read(2): addr=%x ", addr);
272#endif
273		outb (CONF2_ENABLE_PORT , tag.cfg2.enable );
274		outb (CONF2_FORWARD_PORT, tag.cfg2.forward);
275
276		data = inl ((u_short) addr);
277
278		outb (CONF2_ENABLE_PORT,  0);
279		outb (CONF2_FORWARD_PORT, 0);
280		break;
281	};
282
283#ifdef PCI_DEBUG
284	printf ("data=%x\n", data);
285#endif
286
287	return (data);
288}
289
290/*--------------------------------------------------------------------
291**
292**      Write register into configuration space.
293**
294**--------------------------------------------------------------------
295*/
296
297static void
298pcibus_write (pcici_t tag, u_long reg, u_long data)
299{
300	u_long addr;
301
302	if (!tag.cfg1) return;
303
304	switch (pci_mechanism) {
305
306	case 1:
307		addr = tag.cfg1 | (reg & 0xfc);
308#ifdef PCI_DEBUG
309		printf ("pci_conf_write(1): addr=%x data=%x\n",
310			addr, data);
311#endif
312		outl (CONF1_ADDR_PORT, addr);
313		outl (CONF1_DATA_PORT, data);
314		outl (CONF1_ADDR_PORT,   0 );
315		break;
316
317	case 2:
318		addr = tag.cfg2.port | (reg & 0xfc);
319#ifdef PCI_DEBUG
320		printf ("pci_conf_write(2): addr=%x data=%x\n",
321			addr, data);
322#endif
323		outb (CONF2_ENABLE_PORT,  tag.cfg2.enable);
324		outb (CONF2_FORWARD_PORT, tag.cfg2.forward);
325
326		outl ((u_short) addr, data);
327
328		outb (CONF2_ENABLE_PORT,  0);
329		outb (CONF2_FORWARD_PORT, 0);
330		break;
331	};
332}
333
334/*-----------------------------------------------------------------------
335**
336**	Register an interupt handler for a pci device.
337**
338**-----------------------------------------------------------------------
339*/
340
341static int
342pcibus_ihandler_attach (int irq, void(*func)(), int arg, unsigned * maskptr)
343{
344	int result;
345	result = register_intr(
346		irq,		    /* isa irq	    */
347		0,		    /* deviced??    */
348		0,		    /* flags?	    */
349		(inthand2_t*) func, /* handler	    */
350		maskptr,	    /* mask pointer */
351		arg);		    /* handler arg  */
352
353	if (result) {
354		printf ("@@@ pcibus_ihandler_attach: result=%d\n", result);
355		return (result);
356	};
357	update_intr_masks();
358
359	INTREN ((1ul<<irq));
360	return (0);
361}
362
363static int
364pcibus_ihandler_detach (int irq, void(*func)())
365{
366	int result;
367
368	INTRDIS ((1ul<<irq));
369
370	result = unregister_intr (irq, (inthand2_t*) func);
371
372	if (result)
373		printf ("@@@ pcibus_ihandler_detach: result=%d\n", result);
374
375	update_intr_masks();
376
377	return (result);
378}
379
380static int
381pcibus_imask_include (int irq, unsigned* maskptr)
382{
383	unsigned mask;
384
385	if (!maskptr) return (0);
386
387	mask = 1ul << irq;
388
389	if (*maskptr & mask)
390		return (-1);
391
392	INTRMASK (*maskptr, mask);
393	update_intr_masks();
394
395	return (0);
396}
397
398static int
399pcibus_imask_exclude (int irq, unsigned* maskptr)
400{
401	unsigned mask;
402
403	if (!maskptr) return (0);
404
405	mask = 1ul << irq;
406
407	if (! (*maskptr & mask))
408		return (-1);
409
410	*maskptr &= ~mask;
411	update_intr_masks();
412
413	return (0);
414}
415