Deleted Added
full compact
pci_pir.c (31893) pci_pir.c (47307)
1/*
2 * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice unmodified, this list of conditions, and the following
10 * disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
1/*
2 * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice unmodified, this list of conditions, and the following
10 * disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * $Id: pcibus.c,v 1.40 1997/07/20 14:10:08 bde Exp $
26 * $Id: pcibus.c,v 1.41 1997/12/20 09:04:25 se Exp $
27 *
28 */
29
27 *
28 */
29
30#include <sys/types.h>
30#include <sys/param.h>
31#include <sys/systm.h>
31#include <sys/systm.h>
32#include <sys/bus.h>
33#include <sys/kernel.h>
32
33#include <pci/pcivar.h>
34#include <i386/isa/pcibus.h>
35
36#ifdef PCI_COMPAT
37/* XXX this is a terrible hack, which keeps the Tekram AMD SCSI driver happy */
38#define cfgmech pci_mechanism
39int cfgmech;
40#else
41static int cfgmech;
42#endif /* PCI_COMPAT */
43static int devmax;
44
45/* enable configuration space accesses and return data port address */
46
47static int
48pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
49{
50 int dataport = 0;
51
52 if (bus <= PCI_BUSMAX
53 && slot < devmax
54 && func <= PCI_FUNCMAX
55 && reg <= PCI_REGMAX
56 && bytes != 3
57 && (unsigned) bytes <= 4
58 && (reg & (bytes -1)) == 0) {
59 switch (cfgmech) {
60 case 1:
61 outl(CONF1_ADDR_PORT, (1 << 31)
62 | (bus << 16) | (slot << 11)
63 | (func << 8) | (reg & ~0x03));
64 dataport = CONF1_DATA_PORT + (reg & 0x03);
65 break;
66 case 2:
67 outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1));
68 outb(CONF2_FORWARD_PORT, bus);
69 dataport = 0xc000 | (slot << 8) | reg;
70 break;
71 }
72 }
73 return (dataport);
74}
75
76/* disable configuration space accesses */
77
78static void
79pci_cfgdisable(void)
80{
81 switch (cfgmech) {
82 case 1:
83 outl(CONF1_ADDR_PORT, 0);
84 break;
85 case 2:
86 outb(CONF2_ENABLE_PORT, 0);
87 outb(CONF2_FORWARD_PORT, 0);
88 break;
89 }
90}
91
92/* read configuration space register */
93
94int
95pci_cfgread(pcicfgregs *cfg, int reg, int bytes)
96{
97 int data = -1;
98 int port;
99
100 port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes);
101
102 if (port != 0) {
103 switch (bytes) {
104 case 1:
105 data = inb(port);
106 break;
107 case 2:
108 data = inw(port);
109 break;
110 case 4:
111 data = inl(port);
112 break;
113 }
114 pci_cfgdisable();
115 }
116 return (data);
117}
118
119/* write configuration space register */
120
121void
122pci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes)
123{
124 int port;
125
126 port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes);
127 if (port != 0) {
128 switch (bytes) {
129 case 1:
130 outb(port, data);
131 break;
132 case 2:
133 outw(port, data);
134 break;
135 case 4:
136 outl(port, data);
137 break;
138 }
139 pci_cfgdisable();
140 }
141}
142
143/* check whether the configuration mechanism has been correct identified */
144
145static int
146pci_cfgcheck(int maxdev)
147{
148 u_char device;
149
150 if (bootverbose)
151 printf("pci_cfgcheck:\tdevice ");
152
153 for (device = 0; device < maxdev; device++) {
154 unsigned id, class, header;
155 if (bootverbose)
156 printf("%d ", device);
157
158 id = inl(pci_cfgenable(0, device, 0, 0, 4));
159 if (id == 0 || id == -1)
160 continue;
161
162 class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8;
163 if (bootverbose)
164 printf("[class=%06x] ", class);
165 if (class == 0 || (class & 0xf870ff) != 0)
166 continue;
167
168 header = inb(pci_cfgenable(0, device, 0, 14, 1));
169 if (bootverbose)
170 printf("[hdr=%02x] ", header);
171 if ((header & 0x7e) != 0)
172 continue;
173
174 if (bootverbose)
175 printf("is there (id=%08x)\n", id);
176
177 pci_cfgdisable();
178 return (1);
179 }
180 if (bootverbose)
181 printf("-- nothing found\n");
182
183 pci_cfgdisable();
184 return (0);
185}
186
34
35#include <pci/pcivar.h>
36#include <i386/isa/pcibus.h>
37
38#ifdef PCI_COMPAT
39/* XXX this is a terrible hack, which keeps the Tekram AMD SCSI driver happy */
40#define cfgmech pci_mechanism
41int cfgmech;
42#else
43static int cfgmech;
44#endif /* PCI_COMPAT */
45static int devmax;
46
47/* enable configuration space accesses and return data port address */
48
49static int
50pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
51{
52 int dataport = 0;
53
54 if (bus <= PCI_BUSMAX
55 && slot < devmax
56 && func <= PCI_FUNCMAX
57 && reg <= PCI_REGMAX
58 && bytes != 3
59 && (unsigned) bytes <= 4
60 && (reg & (bytes -1)) == 0) {
61 switch (cfgmech) {
62 case 1:
63 outl(CONF1_ADDR_PORT, (1 << 31)
64 | (bus << 16) | (slot << 11)
65 | (func << 8) | (reg & ~0x03));
66 dataport = CONF1_DATA_PORT + (reg & 0x03);
67 break;
68 case 2:
69 outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1));
70 outb(CONF2_FORWARD_PORT, bus);
71 dataport = 0xc000 | (slot << 8) | reg;
72 break;
73 }
74 }
75 return (dataport);
76}
77
78/* disable configuration space accesses */
79
80static void
81pci_cfgdisable(void)
82{
83 switch (cfgmech) {
84 case 1:
85 outl(CONF1_ADDR_PORT, 0);
86 break;
87 case 2:
88 outb(CONF2_ENABLE_PORT, 0);
89 outb(CONF2_FORWARD_PORT, 0);
90 break;
91 }
92}
93
94/* read configuration space register */
95
96int
97pci_cfgread(pcicfgregs *cfg, int reg, int bytes)
98{
99 int data = -1;
100 int port;
101
102 port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes);
103
104 if (port != 0) {
105 switch (bytes) {
106 case 1:
107 data = inb(port);
108 break;
109 case 2:
110 data = inw(port);
111 break;
112 case 4:
113 data = inl(port);
114 break;
115 }
116 pci_cfgdisable();
117 }
118 return (data);
119}
120
121/* write configuration space register */
122
123void
124pci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes)
125{
126 int port;
127
128 port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes);
129 if (port != 0) {
130 switch (bytes) {
131 case 1:
132 outb(port, data);
133 break;
134 case 2:
135 outw(port, data);
136 break;
137 case 4:
138 outl(port, data);
139 break;
140 }
141 pci_cfgdisable();
142 }
143}
144
145/* check whether the configuration mechanism has been correct identified */
146
147static int
148pci_cfgcheck(int maxdev)
149{
150 u_char device;
151
152 if (bootverbose)
153 printf("pci_cfgcheck:\tdevice ");
154
155 for (device = 0; device < maxdev; device++) {
156 unsigned id, class, header;
157 if (bootverbose)
158 printf("%d ", device);
159
160 id = inl(pci_cfgenable(0, device, 0, 0, 4));
161 if (id == 0 || id == -1)
162 continue;
163
164 class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8;
165 if (bootverbose)
166 printf("[class=%06x] ", class);
167 if (class == 0 || (class & 0xf870ff) != 0)
168 continue;
169
170 header = inb(pci_cfgenable(0, device, 0, 14, 1));
171 if (bootverbose)
172 printf("[hdr=%02x] ", header);
173 if ((header & 0x7e) != 0)
174 continue;
175
176 if (bootverbose)
177 printf("is there (id=%08x)\n", id);
178
179 pci_cfgdisable();
180 return (1);
181 }
182 if (bootverbose)
183 printf("-- nothing found\n");
184
185 pci_cfgdisable();
186 return (0);
187}
188
187int
189static int
188pci_cfgopen(void)
189{
190 unsigned long mode1res,oldval1;
191 unsigned char mode2res,oldval2;
192
193 oldval1 = inl(CONF1_ADDR_PORT);
194
195 if (bootverbose) {
196 printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n",
197 oldval1);
198 }
199
200 if ((oldval1 & CONF1_ENABLE_MSK) == 0) {
201
202 cfgmech = 1;
203 devmax = 32;
204
205 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
206 outb(CONF1_ADDR_PORT +3, 0);
207 mode1res = inl(CONF1_ADDR_PORT);
208 outl(CONF1_ADDR_PORT, oldval1);
209
210 if (bootverbose)
211 printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n",
212 mode1res, CONF1_ENABLE_CHK);
213
214 if (mode1res) {
215 if (pci_cfgcheck(32))
216 return (cfgmech);
217 }
218
219 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
220 mode1res = inl(CONF1_ADDR_PORT);
221 outl(CONF1_ADDR_PORT, oldval1);
222
223 if (bootverbose)
224 printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n",
225 mode1res, CONF1_ENABLE_CHK1);
226
227 if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
228 if (pci_cfgcheck(32))
229 return (cfgmech);
230 }
231 }
232
233 oldval2 = inb(CONF2_ENABLE_PORT);
234
235 if (bootverbose) {
236 printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n",
237 oldval2);
238 }
239
240 if ((oldval2 & 0xf0) == 0) {
241
242 cfgmech = 2;
243 devmax = 16;
244
245 outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
246 mode2res = inb(CONF2_ENABLE_PORT);
247 outb(CONF2_ENABLE_PORT, oldval2);
248
249 if (bootverbose)
250 printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n",
251 mode2res, CONF2_ENABLE_CHK);
252
253 if (mode2res == CONF2_ENABLE_RES) {
254 if (bootverbose)
255 printf("pci_open(2a):\tnow trying mechanism 2\n");
256
257 if (pci_cfgcheck(16))
258 return (cfgmech);
259 }
260 }
261
262 cfgmech = 0;
263 devmax = 0;
264 return (cfgmech);
265}
190pci_cfgopen(void)
191{
192 unsigned long mode1res,oldval1;
193 unsigned char mode2res,oldval2;
194
195 oldval1 = inl(CONF1_ADDR_PORT);
196
197 if (bootverbose) {
198 printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n",
199 oldval1);
200 }
201
202 if ((oldval1 & CONF1_ENABLE_MSK) == 0) {
203
204 cfgmech = 1;
205 devmax = 32;
206
207 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
208 outb(CONF1_ADDR_PORT +3, 0);
209 mode1res = inl(CONF1_ADDR_PORT);
210 outl(CONF1_ADDR_PORT, oldval1);
211
212 if (bootverbose)
213 printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n",
214 mode1res, CONF1_ENABLE_CHK);
215
216 if (mode1res) {
217 if (pci_cfgcheck(32))
218 return (cfgmech);
219 }
220
221 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
222 mode1res = inl(CONF1_ADDR_PORT);
223 outl(CONF1_ADDR_PORT, oldval1);
224
225 if (bootverbose)
226 printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n",
227 mode1res, CONF1_ENABLE_CHK1);
228
229 if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
230 if (pci_cfgcheck(32))
231 return (cfgmech);
232 }
233 }
234
235 oldval2 = inb(CONF2_ENABLE_PORT);
236
237 if (bootverbose) {
238 printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n",
239 oldval2);
240 }
241
242 if ((oldval2 & 0xf0) == 0) {
243
244 cfgmech = 2;
245 devmax = 16;
246
247 outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
248 mode2res = inb(CONF2_ENABLE_PORT);
249 outb(CONF2_ENABLE_PORT, oldval2);
250
251 if (bootverbose)
252 printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n",
253 mode2res, CONF2_ENABLE_CHK);
254
255 if (mode2res == CONF2_ENABLE_RES) {
256 if (bootverbose)
257 printf("pci_open(2a):\tnow trying mechanism 2\n");
258
259 if (pci_cfgcheck(16))
260 return (cfgmech);
261 }
262 }
263
264 cfgmech = 0;
265 devmax = 0;
266 return (cfgmech);
267}
268
269static devclass_t pcib_devclass;
270
271static int
272nexus_pcib_probe(device_t dev)
273{
274 if (pci_cfgopen() != 0) {
275 device_set_desc(dev, "PCI host bus adapter");
276
277 device_add_child(dev, "pci", 0, 0);
278 return 0;
279 }
280 return ENXIO;
281}
282
283static device_method_t nexus_pcib_methods[] = {
284 /* Device interface */
285 DEVMETHOD(device_probe, nexus_pcib_probe),
286 DEVMETHOD(device_attach, bus_generic_attach),
287 DEVMETHOD(device_shutdown, bus_generic_shutdown),
288 DEVMETHOD(device_suspend, bus_generic_suspend),
289 DEVMETHOD(device_resume, bus_generic_resume),
290
291 /* Bus interface */
292 DEVMETHOD(bus_print_child, bus_generic_print_child),
293 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
294 DEVMETHOD(bus_release_resource, bus_generic_release_resource),
295 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
296 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
297 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
298 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
299
300 { 0, 0 }
301};
302
303static driver_t nexus_pcib_driver = {
304 "pcib",
305 nexus_pcib_methods,
306 1,
307};
308
309DRIVER_MODULE(pcib, nexus, nexus_pcib_driver, pcib_devclass, 0, 0);