]>
Commit | Line | Data |
---|---|---|
14c7c974 | 1 | /* |
57c72a9a | 2 | * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved. |
14c7c974 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
57c72a9a | 6 | * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights |
4f6e3300 A |
7 | * Reserved. This file contains Original Code and/or Modifications of |
8 | * Original Code as defined in and that are subject to the Apple Public | |
57c72a9a | 9 | * Source License Version 2.0 (the "License"). You may not use this file |
4f6e3300 A |
10 | * except in compliance with the License. Please obtain a copy of the |
11 | * License at http://www.apple.com/publicsource and read it before using | |
12 | * this file. | |
14c7c974 A |
13 | * |
14 | * The Original Code and all software distributed under the License are | |
4f6e3300 | 15 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
14c7c974 A |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
4f6e3300 A |
18 | * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the |
19 | * License for the specific language governing rights and limitations | |
20 | * under the License. | |
14c7c974 A |
21 | * |
22 | * @APPLE_LICENSE_HEADER_END@ | |
23 | */ | |
24 | /* | |
25 | * Copyright (c) 1994 NeXT Computer, Inc. | |
26 | * | |
27 | * PCI bus probing. | |
28 | * | |
29 | * HISTORY | |
30 | * | |
31 | * 03 May 1994 Dean Reece at NeXT | |
32 | * Created | |
33 | */ | |
34 | ||
14c7c974 | 35 | #include "libsaio.h" |
14c7c974 A |
36 | #include "pci.h" |
37 | ||
38 | static BOOL testMethod1(void); | |
39 | static BOOL testMethod2(void); | |
40 | typedef unsigned long (*_pci_bus_method_t)( | |
41 | unsigned char addr, | |
42 | unsigned char dev, | |
43 | unsigned char func, | |
44 | unsigned char bus | |
45 | ); | |
46 | static unsigned long getMethod1( | |
47 | unsigned char addr, | |
48 | unsigned char dev, | |
49 | unsigned char func, | |
50 | unsigned char bus | |
51 | ); | |
52 | static unsigned long getMethod2( | |
53 | unsigned char addr, | |
54 | unsigned char dev, | |
55 | unsigned char func, | |
56 | unsigned char bus | |
57 | ); | |
58 | static unsigned | |
59 | scanBus( | |
60 | unsigned maxBusNum, | |
61 | unsigned maxDevNum, | |
62 | _pci_bus_method_t method, | |
63 | _pci_slot_info_t *slot_array | |
64 | ); | |
65 | ||
66 | _pci_slot_info_t *PCISlotInfo; | |
67 | ||
68 | _pci_slot_info_t * | |
69 | PCI_Bus_Init( | |
70 | PCI_bus_info_t *info /* pass in the PCI boot info struct */ | |
71 | ) | |
72 | { | |
14c7c974 A |
73 | unsigned int maxBusNum = 0, maxDevNum = 0, useMethod = 0; |
74 | _pci_bus_method_t method = NULL; | |
75 | _pci_slot_info_t *slot_array; | |
76 | unsigned nslots; | |
77 | ||
78 | maxBusNum = info->maxBusNum; | |
79 | if (info->BIOSPresent) { | |
80 | if (info->u_bus.s.configMethod1) { | |
81 | useMethod=1; | |
82 | maxDevNum=31; | |
83 | } | |
84 | else if (info->u_bus.s.configMethod2) { | |
85 | useMethod=2; | |
86 | maxDevNum=15; | |
87 | } | |
88 | } | |
89 | else { | |
90 | if (testMethod1()) { | |
91 | useMethod=1; | |
92 | maxDevNum=31; | |
93 | } | |
94 | else if (testMethod2()) { | |
95 | useMethod=2; | |
96 | maxDevNum=15; | |
97 | } | |
98 | } | |
99 | ||
14c7c974 A |
100 | if (useMethod == 1) |
101 | method = getMethod1; | |
102 | else if (useMethod == 2) | |
103 | method = getMethod2; | |
104 | else | |
105 | return NULL; | |
75b89a82 | 106 | |
14c7c974 A |
107 | nslots = scanBus(maxBusNum, maxDevNum, method, NULL); |
108 | slot_array = (_pci_slot_info_t *) | |
109 | malloc(sizeof(_pci_slot_info_t) * nslots +1); | |
110 | (void)scanBus(maxBusNum, maxDevNum, method, slot_array); | |
111 | slot_array[nslots].pid = 0x00; | |
112 | slot_array[nslots].sid = 0x00; | |
113 | PCISlotInfo = slot_array; | |
114 | return slot_array; | |
115 | } | |
116 | ||
117 | static unsigned | |
118 | scanBus( | |
119 | unsigned maxBusNum, | |
120 | unsigned maxDevNum, | |
121 | _pci_bus_method_t method, | |
122 | _pci_slot_info_t *slot_array | |
123 | ) | |
124 | { | |
125 | unsigned int bus, dev, func; | |
126 | unsigned int pid=0, sid=0; | |
127 | unsigned count = 0; | |
128 | ||
129 | for (bus=0; bus<=maxBusNum; bus++) { | |
130 | for (dev=0; dev<=maxDevNum; dev++) { | |
131 | for (func=0; func<8; func++) { | |
132 | pid = (*method)(0x00, dev, func, bus); | |
133 | if ( ((pid&0xffff) != 0xffff) && | |
134 | ((pid&0xffff) != 0x0000) ) { | |
135 | ||
136 | /* device found, do whatever here */ | |
137 | count++; | |
138 | if (slot_array) { | |
139 | sid = (*method)(0x2c, dev, func, bus); | |
140 | slot_array->pid = pid; | |
141 | slot_array->sid = sid; | |
142 | slot_array->dev = dev; | |
143 | slot_array->func = func; | |
144 | slot_array->bus = bus; | |
145 | slot_array++; | |
146 | #if DEBUG | |
147 | printf ("{\"0x%08x:%08x\" = {\"Location\" = \"Dev:%d Func:%d Bus:%d\"; }\n", | |
148 | pid, sid, dev, func, bus); | |
149 | #endif | |
150 | } | |
151 | ||
152 | /* skip 1..7 if not multi-func device */ | |
153 | pid = (*method)(12, dev, func, bus); | |
154 | if ((pid & 0x00800000)==0) break; | |
155 | } | |
156 | } | |
157 | } | |
158 | } | |
159 | return count; | |
160 | } | |
161 | ||
162 | /* defines for Configuration Method #1 (PCI 2.0 Spec, sec 3.6.4.1.1) */ | |
163 | #define PCI_CONFIG_ADDRESS 0x0cf8 | |
164 | #define PCI_CONFIG_DATA 0x0cfc | |
165 | ||
166 | static BOOL | |
167 | testMethod1(void) | |
168 | { | |
169 | unsigned long address, data; | |
170 | ||
171 | for (address = 0x80000000; address < 0x80010000; address += 0x800) { | |
172 | outl (PCI_CONFIG_ADDRESS, address); | |
173 | if (inl (PCI_CONFIG_ADDRESS) != address) { | |
174 | return NO; | |
175 | } | |
176 | data = inl(PCI_CONFIG_DATA); | |
177 | if ((data != PCI_DEFAULT_DATA) && (data != 0x00)) { | |
178 | outl (PCI_CONFIG_ADDRESS, 0); | |
179 | return YES; | |
180 | } | |
181 | } | |
182 | ||
183 | outl (PCI_CONFIG_ADDRESS, 0); | |
184 | return NO; | |
185 | } | |
186 | ||
187 | static unsigned long | |
188 | getMethod1( | |
189 | unsigned char addr, | |
190 | unsigned char dev, | |
191 | unsigned char func, | |
192 | unsigned char bus | |
193 | ) | |
194 | { | |
195 | unsigned long ret=PCI_DEFAULT_DATA; | |
196 | ||
197 | union { | |
198 | unsigned long d; | |
199 | struct { | |
200 | unsigned long addr:8; | |
201 | unsigned long func:3; | |
202 | unsigned long dev:5; | |
203 | unsigned long bus:8; | |
204 | unsigned long key:8; | |
205 | } s; | |
206 | } address; | |
207 | ||
208 | address.d = 0x00000000; | |
209 | address.s.key=0x80; | |
210 | address.s.addr=addr; | |
211 | address.s.dev=dev; | |
212 | address.s.func=func; | |
213 | address.s.bus=bus; | |
214 | outl (PCI_CONFIG_ADDRESS, address.d); | |
215 | ||
216 | if (inl (PCI_CONFIG_ADDRESS) == address.d) | |
217 | ret = inl(PCI_CONFIG_DATA); | |
218 | ||
219 | outl (PCI_CONFIG_ADDRESS, 0); | |
220 | return ret; | |
221 | } | |
222 | ||
223 | ||
224 | /* defines for Configuration Method #2 (PCI 2.0 Spec, sec 3.6.4.1.3) */ | |
225 | #define PCI_CSE_REGISTER 0x0cf8 | |
226 | #define PCI_BUS_FORWARD 0x0cfa | |
227 | ||
228 | static BOOL | |
229 | testMethod2(void) | |
230 | { | |
231 | unsigned long address, data; | |
232 | ||
233 | /* Enable configuration space at I/O ports Cxxx. */ | |
234 | ||
235 | outb (PCI_CSE_REGISTER, 0xF0); | |
236 | if (inb (PCI_CSE_REGISTER) != 0xF0) { | |
237 | return NO; | |
238 | } | |
239 | ||
240 | outb (PCI_BUS_FORWARD, 0x00); | |
241 | if (inb (PCI_BUS_FORWARD) != 0x00) { | |
242 | return NO; | |
243 | } | |
244 | /* Search all devices on the bus. */ | |
245 | for (address = 0xc000; address <= 0xcfff; address += 0x100) { | |
246 | data = inl(address); | |
247 | if ((data != PCI_DEFAULT_DATA) && (data != 0x00)) { | |
248 | outb (PCI_CSE_REGISTER, 0); | |
249 | return YES; | |
250 | } | |
251 | } | |
252 | ||
253 | outb (PCI_CSE_REGISTER, 0); | |
254 | return NO; | |
255 | } | |
256 | ||
257 | static unsigned long | |
258 | getMethod2( | |
259 | unsigned char addr, | |
260 | unsigned char dev, | |
261 | unsigned char func, | |
262 | unsigned char bus | |
263 | ) | |
264 | { | |
265 | unsigned long ret=PCI_DEFAULT_DATA; | |
266 | unsigned short address; | |
267 | unsigned char cse; | |
268 | ||
269 | cse = 0xf0 | (func<<1); | |
270 | outb(PCI_CSE_REGISTER, cse); | |
271 | if (inb(PCI_CSE_REGISTER) == cse) { | |
272 | outb(PCI_BUS_FORWARD, bus); | |
273 | if (inb(PCI_BUS_FORWARD) == bus) { | |
274 | address = 0xc000 | (addr&0xfc) | ((dev&0x0f)<<8); | |
275 | ret = inl(address); | |
276 | } | |
277 | outb(PCI_BUS_FORWARD, 0x00); | |
278 | } | |
279 | outb(PCI_CSE_REGISTER, 0x00); | |
280 | ||
281 | return ret; | |
282 | } | |
283 |