]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/amd64/pci/pci_cfgreg.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / amd64 / pci / pci_cfgreg.c
1 /*-
2  * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
3  * Copyright (c) 2000, Michael Smith <msmith@freebsd.org>
4  * Copyright (c) 2000, BSDi
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice unmodified, this list of conditions, and the following
12  *    disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/bus.h>
35 #include <sys/lock.h>
36 #include <sys/mutex.h>
37 #include <dev/pci/pcivar.h>
38 #include <dev/pci/pcireg.h>
39 #include <machine/pci_cfgreg.h>
40
41 static int      pcireg_cfgread(int bus, int slot, int func, int reg, int bytes);
42 static void     pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes);
43
44 static struct mtx pcicfg_mtx;
45
46 /* 
47  * Initialise access to PCI configuration space 
48  */
49 int
50 pci_cfgregopen(void)
51 {
52         static int              opened = 0;
53
54         if (opened)
55                 return (1);
56         mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN);
57         opened = 1;
58         return (1);
59 }
60
61 /* 
62  * Read configuration space register
63  */
64 u_int32_t
65 pci_cfgregread(int bus, int slot, int func, int reg, int bytes)
66 {
67         uint32_t line;
68
69         /*
70          * Some BIOS writers seem to want to ignore the spec and put
71          * 0 in the intline rather than 255 to indicate none.  Some use
72          * numbers in the range 128-254 to indicate something strange and
73          * apparently undocumented anywhere.  Assume these are completely bogus
74          * and map them to 255, which the rest of the PCI code recognizes as
75          * as an invalid IRQ.
76          */
77         if (reg == PCIR_INTLINE && bytes == 1) {
78                 line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1);
79                 if (line == 0 || line >= 128)
80                         line = PCI_INVALID_IRQ;
81                 return (line);
82         }
83         return (pcireg_cfgread(bus, slot, func, reg, bytes));
84 }
85
86 /* 
87  * Write configuration space register 
88  */
89 void
90 pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes)
91 {
92
93         pcireg_cfgwrite(bus, slot, func, reg, data, bytes);
94 }
95
96 /* 
97  * Configuration space access using direct register operations
98  */
99
100 /* enable configuration space accesses and return data port address */
101 static int
102 pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
103 {
104         int dataport = 0;
105
106         if (bus <= PCI_BUSMAX && slot < 32 && func <= PCI_FUNCMAX &&
107             reg <= PCI_REGMAX && bytes != 3 && (unsigned) bytes <= 4 &&
108             (reg & (bytes - 1)) == 0) {
109                 outl(CONF1_ADDR_PORT, (1 << 31) | (bus << 16) | (slot << 11) 
110                     | (func << 8) | (reg & ~0x03));
111                 dataport = CONF1_DATA_PORT + (reg & 0x03);
112         }
113         return (dataport);
114 }
115
116 /* disable configuration space accesses */
117 static void
118 pci_cfgdisable(void)
119 {
120
121         /*
122          * Do nothing.  Writing a 0 to the address port can apparently
123          * confuse some bridges and cause spurious access failures.
124          */
125 }
126
127 static int
128 pcireg_cfgread(int bus, int slot, int func, int reg, int bytes)
129 {
130         int data = -1;
131         int port;
132
133         mtx_lock_spin(&pcicfg_mtx);
134         port = pci_cfgenable(bus, slot, func, reg, bytes);
135         if (port != 0) {
136                 switch (bytes) {
137                 case 1:
138                         data = inb(port);
139                         break;
140                 case 2:
141                         data = inw(port);
142                         break;
143                 case 4:
144                         data = inl(port);
145                         break;
146                 }
147                 pci_cfgdisable();
148         }
149         mtx_unlock_spin(&pcicfg_mtx);
150         return (data);
151 }
152
153 static void
154 pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
155 {
156         int port;
157
158         mtx_lock_spin(&pcicfg_mtx);
159         port = pci_cfgenable(bus, slot, func, reg, bytes);
160         if (port != 0) {
161                 switch (bytes) {
162                 case 1:
163                         outb(port, data);
164                         break;
165                 case 2:
166                         outw(port, data);
167                         break;
168                 case 4:
169                         outl(port, data);
170                         break;
171                 }
172                 pci_cfgdisable();
173         }
174         mtx_unlock_spin(&pcicfg_mtx);
175 }