source: trunk/src/os2ahci/pci.c@ 81

Last change on this file since 81 was 81, checked in by chris, 14 years ago

Version 1.07
============

  • Changed resource allocation such that all PCI BARs will be registered, even the ones which are related to legacy interfaces, to prevent other drivers from accessing the adapter. This didn't work as well as anticipated because DANIS506.ADD currently doesn't skip an adapter just because resources could not be registered but this can be fixed, of course, and the end result would be that by simply changing the load order of DANIS506.ADD and OS2AHCI.ADD would be sufficient to determine which driver controls AHCI-capable SATA adapters.
File size: 43.5 KB
Line 
1/******************************************************************************
2 * PCI.c - PCI constants and detection code for os2ahci driver
3 *
4 * Copyright (c) 2010 Christian Mueller, Markus Thielen.
5 * Parts copied from/inspired by the LINUX ahci driver;
6 * those parts are (c) Linux AHCI/ATA maintainers
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include "os2ahci.h"
24
25/* -------------------------- macros and constants ------------------------- */
26
27/* offset of PCI base address register (BAR) in the PCI config space */
28#define PCI_BAR(reg) (UCHAR) (0x10 + (reg) * sizeof(u32))
29
30/******************************************************************************
31 * OEMHLP constants for PCI access
32 */
33#define GENERIC_IOCTL 0x10
34#define OH_CATEGORY 0x00
35#define OH_FUNC_PCI 0x0b
36
37/* subfunctions */
38#define OH_BIOS_INFO 0x00
39#define OH_FIND_DEVICE 0x01
40#define OH_FIND_CLASS 0x02
41#define OH_READ_CONFIG 0x03
42#define OH_WRITE_CONFIG 0x04
43
44/* return codes */
45#define OH_SUCCESS 0x00
46#define OH_NOT_SUPPORTED 0x81
47#define OH_BAD_VENDOR 0x83
48#define OH_NOT_FOUND 0x86
49#define OH_BAD_REGISTER 0x87
50
51/* ------------------------ typedefs and structures ------------------------ */
52
53/******************************************************************************
54 * OEMHLP IOCtl parameter union. The parameter area is generally used as input
55 * to the OEMHLP IOCtl calls.
56 */
57typedef union {
58
59 /* query PCI BIOS information" */
60 struct {
61 UCHAR subfunction;
62 } bios_info;
63
64 /* find PCI device */
65 struct {
66 UCHAR subfunction;
67 USHORT device;
68 USHORT vendor;
69 UCHAR index;
70 } find_device;
71
72 /* find PCI class code */
73 struct {
74 UCHAR subfunction;
75 ULONG class;
76 UCHAR index;
77 } find_class;
78
79 /* read PCI configuration space */
80 struct {
81 UCHAR subfunction;
82 UCHAR bus;
83 UCHAR dev_func;
84 UCHAR reg;
85 UCHAR size;
86 } read_config;
87
88 /* write PCI configuration space */
89 struct {
90 UCHAR subfunction;
91 UCHAR bus;
92 UCHAR dev_func;
93 UCHAR reg;
94 UCHAR size;
95 ULONG data;
96 } write_config;
97
98} OH_PARM;
99
100/******************************************************************************
101 * OEMHLP IOCtl data union. The data area is generally used as output from the
102 * OEMHLP IOCtl calls.
103 */
104typedef union {
105
106 /* query PCI BIOS information" */
107 struct {
108 UCHAR rc;
109 UCHAR hw_mech;
110 UCHAR major_version;
111 UCHAR minor_version;
112 UCHAR last_bus;
113 } bios_info;
114
115 /* find PCI device */
116 struct {
117 UCHAR rc;
118 UCHAR bus;
119 UCHAR dev_func;
120 } find_device;
121
122 /* find PCI class code */
123 struct {
124 UCHAR rc;
125 UCHAR bus;
126 UCHAR dev_func;
127 } find_class;
128
129 /* read PCI confguration space */
130 struct {
131 UCHAR rc;
132 ULONG data;
133 } read_config;
134
135 /* write PCI confguration space */
136 struct {
137 UCHAR rc;
138 } write_config;
139
140} OH_DATA;
141
142/* -------------------------- function prototypes -------------------------- */
143
144static void add_pci_device (PCI_ID *pci_id, OH_DATA _far *data);
145static UCHAR pci_read_conf (UCHAR bus, UCHAR dev_func, UCHAR indx,
146 UCHAR size, ULONG _far *val);
147static UCHAR pci_write_conf (UCHAR bus, UCHAR dev_func, UCHAR indx, UCHAR size,
148 ULONG val);
149static int oemhlp_call (UCHAR subfunction, OH_PARM _far *parm,
150 OH_DATA _far *data);
151static long bar_resource (UCHAR bus, UCHAR dev_func,
152 RESOURCESTRUCT _far *resource, int i);
153static char *rmerr (APIRET ret);
154
155/* ------------------------ global/static variables ------------------------ */
156
157/******************************************************************************
158 * chipset/controller name strings
159 */
160static char chip_esb2[] = "ESB2";
161static char chip_ich8[] = "ICH8";
162static char chip_ich8m[] = "ICH8M";
163static char chip_ich9[] = "ICH9";
164static char chip_ich9m[] = "ICH9M";
165static char chip_ich10[] = "ICH10";
166static char chip_pchahci[] = "PCH AHCI";
167static char chip_pchraid[] = "PCH RAID";
168static char chip_tolapai[] = "Tolapai";
169static char chip_sb600[] = "SB600";
170static char chip_sb700[] = "SB700/800";
171static char chip_vt8251[] = "VT8251";
172static char chip_mcp65[] = "MCP65";
173static char chip_mcp67[] = "MCP67";
174static char chip_mcp73[] = "MCP73";
175static char chip_mcp77[] = "MCP77";
176static char chip_mcp79[] = "MCP79";
177static char chip_mcp89[] = "MCP689";
178static char chip_sis968[] = "968";
179
180static char s_generic[] = "Generic";
181
182/******************************************************************************
183 * other strings
184 */
185static char s_already_claimed[] = "Warning: device already claimed by another driver.\n";
186
187
188
189/******************************************************************************
190 * PCI vendor and device IDs for known AHCI adapters. Copied from the Linux
191 * AHCI driver.
192 */
193
194PCI_ID pci_ids[] = {
195
196 /* Intel
197 * NOTE: ICH5 controller does NOT support AHCI, so we do
198 * not add it here! */
199 { PCI_VDEVICE(INTEL, 0x2652), board_ahci, "ICH6" }, /* ICH6 */
200 { PCI_VDEVICE(INTEL, 0x2653), board_ahci, "ICH6M" }, /* ICH6M */
201 { PCI_VDEVICE(INTEL, 0x27c1), board_ahci, "ICH7" }, /* ICH7 */
202 { PCI_VDEVICE(INTEL, 0x27c5), board_ahci, "ICH7M" }, /* ICH7M */
203 { PCI_VDEVICE(INTEL, 0x27c3), board_ahci, "ICH7R" }, /* ICH7R */
204 { PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr, "ULiM5288" }, /* ULi M5288 */
205 { PCI_VDEVICE(INTEL, 0x2681), board_ahci, chip_esb2 }, /* ESB2 */
206 { PCI_VDEVICE(INTEL, 0x2682), board_ahci, chip_esb2 }, /* ESB2 */
207 { PCI_VDEVICE(INTEL, 0x2683), board_ahci, chip_esb2 }, /* ESB2 */
208 { PCI_VDEVICE(INTEL, 0x27c6), board_ahci, "ICH7MDH" }, /* ICH7-M DH */
209 { PCI_VDEVICE(INTEL, 0x2821), board_ahci, chip_ich8 }, /* ICH8 */
210 { PCI_VDEVICE(INTEL, 0x2822), board_ahci_nosntf, chip_ich8 }, /* ICH8 */
211 { PCI_VDEVICE(INTEL, 0x2824), board_ahci, chip_ich8 }, /* ICH8 */
212 { PCI_VDEVICE(INTEL, 0x2829), board_ahci, chip_ich8m }, /* ICH8M */
213 { PCI_VDEVICE(INTEL, 0x282a), board_ahci, chip_ich8m }, /* ICH8M */
214 { PCI_VDEVICE(INTEL, 0x2922), board_ahci, chip_ich9 }, /* ICH9 */
215 { PCI_VDEVICE(INTEL, 0x2923), board_ahci, chip_ich9 }, /* ICH9 */
216 { PCI_VDEVICE(INTEL, 0x2924), board_ahci, chip_ich9 }, /* ICH9 */
217 { PCI_VDEVICE(INTEL, 0x2925), board_ahci, chip_ich9 }, /* ICH9 */
218 { PCI_VDEVICE(INTEL, 0x2927), board_ahci, chip_ich9 }, /* ICH9 */
219 { PCI_VDEVICE(INTEL, 0x2929), board_ahci, chip_ich9m }, /* ICH9M */
220 { PCI_VDEVICE(INTEL, 0x292a), board_ahci, chip_ich9m }, /* ICH9M */
221 { PCI_VDEVICE(INTEL, 0x292b), board_ahci, chip_ich9m }, /* ICH9M */
222 { PCI_VDEVICE(INTEL, 0x292c), board_ahci, chip_ich9m }, /* ICH9M */
223 { PCI_VDEVICE(INTEL, 0x292f), board_ahci, chip_ich9m }, /* ICH9M */
224 { PCI_VDEVICE(INTEL, 0x294d), board_ahci, chip_ich9 }, /* ICH9 */
225 { PCI_VDEVICE(INTEL, 0x294e), board_ahci, chip_ich9m }, /* ICH9M */
226 { PCI_VDEVICE(INTEL, 0x502a), board_ahci, chip_tolapai }, /* Tolapai */
227 { PCI_VDEVICE(INTEL, 0x502b), board_ahci, chip_tolapai }, /* Tolapai */
228 { PCI_VDEVICE(INTEL, 0x3a05), board_ahci, chip_ich10 }, /* ICH10 */
229 { PCI_VDEVICE(INTEL, 0x3a22), board_ahci, chip_ich10 }, /* ICH10 */
230 { PCI_VDEVICE(INTEL, 0x3a25), board_ahci, chip_ich10 }, /* ICH10 */
231 { PCI_VDEVICE(INTEL, 0x3b22), board_ahci, chip_pchahci }, /* PCH AHCI */
232 { PCI_VDEVICE(INTEL, 0x3b23), board_ahci, chip_pchahci }, /* PCH AHCI */
233 { PCI_VDEVICE(INTEL, 0x3b24), board_ahci, chip_pchraid }, /* PCH RAID */
234 { PCI_VDEVICE(INTEL, 0x3b25), board_ahci, chip_pchraid }, /* PCH RAID */
235 { PCI_VDEVICE(INTEL, 0x3b29), board_ahci, chip_pchahci }, /* PCH AHCI */
236 { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci, chip_pchraid }, /* PCH RAID */
237 { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci, chip_pchraid }, /* PCH RAID */
238 { PCI_VDEVICE(INTEL, 0x3b2f), board_ahci, chip_pchahci }, /* PCH AHCI */
239
240 /* JMicron 360/1/3/5/6, match class to avoid IDE function */
241 { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
242 PCI_CLASS_STORAGE_SATA_AHCI, 0xffffffL, board_ahci_ign_iferr, "360" },
243
244 /* ATI */
245 { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600, chip_sb600 }, /* ATI SB600 */
246 { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
247 { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
248 { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
249 { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
250 { PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
251 { PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
252
253 /* AMD */
254 { PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD Hudson-2 */
255 /* AMD is using RAID class only for ahci controllers */
256 { PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
257 PCI_CLASS_STORAGE_RAID << 8, 0xffffffL, board_ahci, "Hudson2" },
258
259 /* VIA */
260 { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251, chip_vt8251 }, /* VIA VT8251 */
261 { PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251, chip_vt8251 }, /* VIA VT8251 */
262
263 /* NVIDIA */
264 { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
265 { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
266 { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
267 { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
268 { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
269 { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
270 { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
271 { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
272 { PCI_VDEVICE(NVIDIA, 0x0550), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
273 { PCI_VDEVICE(NVIDIA, 0x0551), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
274 { PCI_VDEVICE(NVIDIA, 0x0552), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
275 { PCI_VDEVICE(NVIDIA, 0x0553), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
276 { PCI_VDEVICE(NVIDIA, 0x0554), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
277 { PCI_VDEVICE(NVIDIA, 0x0555), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
278 { PCI_VDEVICE(NVIDIA, 0x0556), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
279 { PCI_VDEVICE(NVIDIA, 0x0557), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
280 { PCI_VDEVICE(NVIDIA, 0x0558), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
281 { PCI_VDEVICE(NVIDIA, 0x0559), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
282 { PCI_VDEVICE(NVIDIA, 0x055a), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
283 { PCI_VDEVICE(NVIDIA, 0x055b), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
284 { PCI_VDEVICE(NVIDIA, 0x0580), board_ahci_yesncq, chip_mcp67 }, /* Linux ID */
285 { PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
286 { PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
287 { PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
288 { PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
289 { PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
290 { PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
291 { PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
292 { PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
293 { PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
294 { PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
295 { PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
296 { PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
297 { PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci, chip_mcp77 }, /* MCP77 */
298 { PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci, chip_mcp77 }, /* MCP77 */
299 { PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci, chip_mcp77 }, /* MCP77 */
300 { PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci, chip_mcp77 }, /* MCP77 */
301 { PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci, chip_mcp77 }, /* MCP77 */
302 { PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci, chip_mcp77 }, /* MCP77 */
303 { PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci, chip_mcp77 }, /* MCP77 */
304 { PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci, chip_mcp77 }, /* MCP77 */
305 { PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci, chip_mcp77 }, /* MCP77 */
306 { PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci, chip_mcp77 }, /* MCP77 */
307 { PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci, chip_mcp77 }, /* MCP77 */
308 { PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci, chip_mcp77 }, /* MCP77 */
309 { PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci, chip_mcp79 }, /* MCP79 */
310 { PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci, chip_mcp79 }, /* MCP79 */
311 { PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci, chip_mcp79 }, /* MCP79 */
312 { PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci, chip_mcp79 }, /* MCP79 */
313 { PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci, chip_mcp79 }, /* MCP79 */
314 { PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci, chip_mcp79 }, /* MCP79 */
315 { PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci, chip_mcp79 }, /* MCP79 */
316 { PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci, chip_mcp79 }, /* MCP79 */
317 { PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci, chip_mcp79 }, /* MCP79 */
318 { PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci, chip_mcp79 }, /* MCP79 */
319 { PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci, chip_mcp79 }, /* MCP79 */
320 { PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci, chip_mcp79 }, /* MCP79 */
321 { PCI_VDEVICE(NVIDIA, 0x0d84), board_ahci, chip_mcp89 }, /* MCP89 */
322 { PCI_VDEVICE(NVIDIA, 0x0d85), board_ahci, chip_mcp89 }, /* MCP89 */
323 { PCI_VDEVICE(NVIDIA, 0x0d86), board_ahci, chip_mcp89 }, /* MCP89 */
324 { PCI_VDEVICE(NVIDIA, 0x0d87), board_ahci, chip_mcp89 }, /* MCP89 */
325 { PCI_VDEVICE(NVIDIA, 0x0d88), board_ahci, chip_mcp89 }, /* MCP89 */
326 { PCI_VDEVICE(NVIDIA, 0x0d89), board_ahci, chip_mcp89 }, /* MCP89 */
327 { PCI_VDEVICE(NVIDIA, 0x0d8a), board_ahci, chip_mcp89 }, /* MCP89 */
328 { PCI_VDEVICE(NVIDIA, 0x0d8b), board_ahci, chip_mcp89 }, /* MCP89 */
329 { PCI_VDEVICE(NVIDIA, 0x0d8c), board_ahci, chip_mcp89 }, /* MCP89 */
330 { PCI_VDEVICE(NVIDIA, 0x0d8d), board_ahci, chip_mcp89 }, /* MCP89 */
331 { PCI_VDEVICE(NVIDIA, 0x0d8e), board_ahci, chip_mcp89 }, /* MCP89 */
332 { PCI_VDEVICE(NVIDIA, 0x0d8f), board_ahci, chip_mcp89 }, /* MCP89 */
333
334 /* SiS */
335 { PCI_VDEVICE(SI, 0x1184), board_ahci, "966" }, /* SiS 966 */
336 { PCI_VDEVICE(SI, 0x1185), board_ahci, chip_sis968 }, /* SiS 968 */
337 { PCI_VDEVICE(SI, 0x0186), board_ahci, chip_sis968 }, /* SiS 968 */
338
339 /* Marvell */
340 { PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv, "6145" }, /* 6145 */
341 { PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv, "6121" }, /* 6121 */
342
343 /* Promise */
344 { PCI_VDEVICE(PROMISE, 0x3f20), board_ahci, "PDC42819" }, /* PDC42819 */
345
346 /* Generic, PCI class code for AHCI */
347 { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
348 PCI_CLASS_STORAGE_SATA_AHCI, 0xffffffL, board_ahci, s_generic },
349
350 /* end of list, including a few slots to define custom adapters (10) */
351 { 0, 0, 0, 0, 0, 0, 0, NULL },
352 { 0, 0, 0, 0, 0, 0, 0, NULL },
353 { 0, 0, 0, 0, 0, 0, 0, NULL },
354 { 0, 0, 0, 0, 0, 0, 0, NULL },
355 { 0, 0, 0, 0, 0, 0, 0, NULL },
356 { 0, 0, 0, 0, 0, 0, 0, NULL },
357 { 0, 0, 0, 0, 0, 0, 0, NULL },
358 { 0, 0, 0, 0, 0, 0, 0, NULL },
359 { 0, 0, 0, 0, 0, 0, 0, NULL },
360 { 0, 0, 0, 0, 0, 0, 0, NULL },
361
362 { 0, 0, 0, 0, 0, 0, 0, NULL }
363};
364
365/******************************************************************************
366 * OEMHLP$ is used by OS/2 to provide access to OEM-specific machine resources
367 * like PCI BIOS access. We're using this to enumerate the PCI bus. Due to
368 * BIOS bugs, it may be necessary to use I/O operations for this purpose but
369 * so far I think this is only relevant for rather old PCs and SATA is not
370 * expected to be a priority on those machines.
371 */
372static IDCTABLE oemhlp; /* OEMHLP$ IDC entry point */
373
374/* ----------------------------- start of code ----------------------------- */
375
376/******************************************************************************
377 * Add specified PCI vendor and device ID to the list of supported AHCI
378 * controllers. Please note that the last slot in pci_ids needs to remain
379 * empty because it's used as end marker.
380 */
381int add_pci_id(u16 vendor, u16 device)
382{
383 int max_slot = sizeof(pci_ids) / sizeof(*pci_ids) - 2;
384 int i;
385
386 /* search for last used slot in 'pci_ids' */
387 for (i = max_slot; i >= 0 && pci_ids[i].vendor == 0; i--);
388 if (i >= max_slot) {
389 /* all slots in use */
390 return(-1);
391 }
392
393 /* use slot after the last used slot */
394 i++;
395 pci_ids[i].vendor = vendor;
396 pci_ids[i].device = device;
397 pci_ids[i].board = board_ahci;
398 pci_ids[i].chipname = s_generic;
399 return(0);
400}
401
402/******************************************************************************
403 * Scan PCI bus using OEMHLP$ IOCTLs and build adapter list.
404 */
405void scan_pci_bus(void)
406{
407 OH_PARM parm;
408 OH_DATA data;
409 UCHAR index;
410 UCHAR rc;
411 int ad_indx = 0;
412 int i;
413 int n;
414
415 ddprintf("scanning PCI bus...\n");
416
417 /* verify that we have a PCI system */
418 memset(&parm, 0x00, sizeof(parm));
419 if (oemhlp_call(OH_BIOS_INFO, &parm, &data) != OH_SUCCESS) {
420 cprintf("couldn't get PCI BIOS information\n");
421 return;
422 }
423
424 /* Go through the list of PCI IDs and search for each device
425 *
426 * NOTES:
427 *
428 * - When searching via class code, the OEMHLP$ interface doesn't allow
429 * setting a bitmask to look for individual portions of class code,
430 * subclass code and programming interface. However, all bitmasks in the
431 * PCI list currently use 0xffffff, thus this should not be a problem at
432 * this point in time.
433 *
434 * - Scanning via OEMHLP$ seems rather slow, at least in the virtual
435 * machine I'm currenly using to test this driver. Thus, class code
436 * scans are preferred unless the option "-t" (thorough_scan) has been
437 * specified. The assumption is that most, if not all, modern AHCI
438 * adapters have the correct class code (PCI_CLASS_STORAGE_SATA_AHCI).
439 */
440 for (i = 0; pci_ids[i].vendor != 0; i++) {
441 index = 0;
442 do {
443 if (pci_ids[i].device == PCI_ANY_ID || pci_ids[i].vendor == PCI_ANY_ID) {
444 /* look for class code */
445 memset(&parm, 0x00, sizeof(parm));
446 parm.find_class.class = pci_ids[i].class;
447 parm.find_class.index = index;
448 rc = oemhlp_call(OH_FIND_CLASS, &parm, &data);
449
450 } else if (thorough_scan) {
451 /* look for this specific vendor and device ID */
452 memset(&parm, 0x00, sizeof(parm));
453 parm.find_device.device = pci_ids[i].device;
454 parm.find_device.vendor = pci_ids[i].vendor;
455 parm.find_device.index = index;
456 rc = oemhlp_call(OH_FIND_DEVICE, &parm, &data);
457
458 } else {
459 rc = OH_NOT_FOUND;
460 }
461
462 if (rc == OH_SUCCESS) {
463 /* found a device */
464 int already_found = 0;
465
466 /* increment index for next loop */
467 if (++index > 180) {
468 /* something's wrong here... */
469 return;
470 }
471
472 /* check whether we already found this device */
473 for (n = 0; n < ad_info_cnt; n++) {
474 if (ad_infos[n].bus == data.find_device.bus &&
475 ad_infos[n].dev_func == data.find_device.dev_func) {
476 /* this device has already been found (e.g. via thorough scan) */
477 already_found = 1;
478 break;
479 }
480 }
481
482 if (already_found || (ad_ignore & (1U << ad_indx++))) {
483 /* ignore this device; it has either already been found via a
484 * thorough scan or has been specified to be ignored via command
485 * line option */
486 continue;
487 }
488
489 /* add this PCI device to ad_infos[] */
490 add_pci_device(pci_ids + i, &data);
491 }
492
493 } while (rc == OH_SUCCESS);
494 }
495}
496
497/******************************************************************************
498 * Enable interrupt generation. PCI 2.3 added a bit which allows disabling
499 * interrupt generation for a device. This function clears the corresponding
500 * bit in the configuration space command register.
501 */
502int pci_enable_int(UCHAR bus, UCHAR dev_func)
503{
504 ULONG tmp;
505
506 if (pci_read_conf (bus, dev_func, 4, sizeof(u32), &tmp) != OH_SUCCESS ||
507 pci_write_conf(bus, dev_func, 4, sizeof(u32), tmp & ~(1UL << 10)) != OH_SUCCESS) {
508 return(-1);
509 }
510 return(0);
511}
512
513/******************************************************************************
514 * Hack to set up proper IRQ mappings in the emulated PIIX3 ISA bridge in
515 * VirtualBox (for some reason, the first mapped IRQ is 0x80 without this
516 * hack).
517 */
518void pci_hack_virtualbox(void)
519{
520 ULONG irq = 0;
521
522 if (pci_read_conf(0, 0x08, 0x60, 1, &irq) == OH_SUCCESS && irq == 0x80) {
523 /* set IRQ for first device/func to 11 */
524 dprintf("hacking virtualbox PIIX3 PCI to ISA bridge IRQ mapping\n");
525 irq = ad_infos[0].irq;
526 pci_write_conf(0, 0x08, 0x60, 1, irq);
527 }
528}
529
530/******************************************************************************
531 * Add a single PCI device to the list of adapters.
532 */
533static void add_pci_device(PCI_ID *pci_id, OH_DATA _far *data)
534{
535 char rc_list_buf[sizeof(AHRESOURCE) + sizeof(HRESOURCE) * 15];
536 AHRESOURCE _far *rc_list = (AHRESOURCE _far *) rc_list_buf;
537 RESOURCESTRUCT resource;
538 ADAPTERSTRUCT adapter;
539 ADJUNCT adj;
540 AD_INFO *ad_info;
541 APIRET ret;
542 UCHAR bus = data->find_class.bus;
543 UCHAR dev_func = data->find_class.dev_func;
544 ULONG val;
545 SEL gdt[PORT_DMA_BUF_SEGS + 1];
546 char tmp[40];
547 u16 device;
548 u16 vendor;
549 u32 class;
550 int irq;
551 int pin;
552 int i;
553
554 /*****************************************************************************
555 * Part 1: Get further information about the device to be added; PCI ID...
556 */
557 if (pci_read_conf(bus, dev_func, 0x00, sizeof(ULONG), &val) != OH_SUCCESS) {
558 return;
559 }
560 device = (u16) (val >> 16);
561 vendor = (u16) (val & 0xffff);
562
563 /* ... and class code */
564 if (pci_read_conf(bus, dev_func, 0x08, sizeof(ULONG), &val) != OH_SUCCESS) {
565 return;
566 }
567 class = (u32) (val >> 8);
568
569 if (pci_id->device == PCI_ANY_ID) {
570 /* We found this device in a wildcard search. There are two possible
571 * reasons which require a different handling:
572 *
573 * 1) This device uses a non-standard PCI class and has been identified
574 * with the corresponding class in pci_ids[] (e.g. the entry
575 * PCI_VENDOR_ID_JMICRON), but there is a vendor ID in pci_ids[]. In
576 * this case, we need to verify that the vendor is correct (see
577 * comments regarding OEMHLP limitations in 'scan_pci_bus()')
578 *
579 * 2) This device was identified using a generic PCI class for AHCI
580 * adapters such as PCI_CLASS_STORAGE_SATA_AHCI and we need to map
581 * the device and vendor ID to the corresponding index in pci_ids[]
582 * if there is such an entry; the index passed to this function will
583 * be the generic class-based index which is fine as long as there's
584 * not special treatment required as indicated by the board_*
585 * constants in pci_ids[]...
586 *
587 * The main reason for this kludge is that it seems as if OEMHLP$
588 * is rather slow searching for PCI devices, adding around 30s
589 * to the boot time when scanning for individual AHCI PCI IDs. Thus,
590 * the OS2AHCI driver avoids this kind of scan in favor of a class-
591 * based scan (unless overridden with the "/T" option).
592 */
593 if (pci_id->vendor != PCI_ANY_ID) {
594 /* case 1: the vendor is known but we found the PCI device using a class
595 * search; verify vendor matches the one in pci_ids[]
596 */
597 if (pci_id->vendor != vendor) {
598 /* vendor doesn't match */
599 return;
600 }
601
602 } else {
603 /* case 2: we found this device using a generic class search; if the
604 * device/vendor is listed in pci_ids[], use this entry in favor of the
605 * one passed in 'pci_id'
606 */
607 for (i = 0; pci_ids[i].vendor != 0; i++) {
608 if (pci_ids[i].device == device && pci_ids[i].vendor == vendor) {
609 pci_id = pci_ids + i;
610 break;
611 }
612 }
613 }
614 }
615
616 /* found a supported AHCI device */
617 cprintf("found AHCI device: %s %s (%04x:%04x)\n"
618 " class:0x%06lx bus:%d devfunc:0x%02x\n",
619 vendor_from_id(vendor), device_from_id(device),
620 vendor, device,
621 class, bus, dev_func);
622
623 /* make sure we got room in the adapter information array */
624 if (ad_info_cnt >= MAX_AD - 1) {
625 cprintf("error: too many AHCI devices\n");
626 return;
627 }
628
629 /****************************************************************************
630 * Part 2: Determine resource requirements and allocate resources with the
631 * OS/2 resource manager. While doing so, some of the entries of the
632 * corresponding slot in the AD_INFO array, namely resource manager
633 * handles, are initialized so we need prepare the slot.
634 *
635 * NOTE: While registering resources with the resource manager, each new
636 * resource is added to the corresponding rc_list.hResource[] slot.
637 * rc_list is used further down to associate resources to adapters
638 * when the adapter itself is registered with the OS/2 resource
639 * manager.
640 */
641 ad_info = ad_infos + ad_info_cnt;
642 memset(ad_info, 0x00, sizeof(*ad_info));
643 rc_list->NumResource = 0;
644
645 /* Register IRQ with resource manager
646 *
647 * NOTE: We rely on the IRQ number saved in the PCI config space by the PCI
648 * BIOS. There's no reliable way to find out the IRQ number in any
649 * other way unless we start using message-driven interrupts (which
650 * is out of scope for the time being).
651 */
652 if (pci_read_conf(bus, dev_func, 0x3c, sizeof(u32), &val) != OH_SUCCESS) {
653 return;
654 }
655 irq = (int) (val & 0xff);
656 pin = (int) ((val >> 8) & 0xff);
657
658 memset(&resource, 0x00, sizeof(resource));
659 resource.ResourceType = RS_TYPE_IRQ;
660 resource.IRQResource.IRQLevel = irq;
661 resource.IRQResource.PCIIrqPin = pin;
662 resource.IRQResource.IRQFlags = RS_IRQ_SHARED;
663
664 ret = RMAllocResource(rm_drvh, &ad_info->rm_irq, &resource);
665 if (ret != RMRC_SUCCESS) {
666 cprintf("error: couldn't register IRQ %d (rc = %s)\n", irq, rmerr(ret));
667 return;
668 }
669 rc_list->hResource[rc_list->NumResource++] = ad_info->rm_irq;
670
671 /* Allocate all I/O and MMIO addresses offered by this device. In theory,
672 * we need only BAR #5, the AHCI MMIO BAR, but in order to prevent any
673 * other driver from hijacking our device and accessing it via legacy
674 * registers we'll reserve anything we can find.
675 */
676 for (i = 0; i < sizeof(ad_info->rm_bars) / sizeof(*ad_info->rm_bars); i++) {
677 long len = bar_resource(bus, dev_func, &resource, i);
678
679 if (len < 0) {
680 /* something went wrong */
681 goto add_pci_fail;
682 }
683 if (len == 0) {
684 /* this BAR is unused */
685 continue;
686 }
687
688 if (i == AHCI_PCI_BAR) {
689 if (resource.ResourceType != RS_TYPE_MEM) {
690 cprintf("error: BAR #5 must be an MMIO region\n");
691 goto add_pci_fail;
692 }
693 /* save this BAR's address as MMIO address */
694 ad_info->mmio_phys = resource.MEMResource.MemBase;
695 ad_info->mmio_size = resource.MEMResource.MemSize;
696 }
697
698 /* register [MM]IO region with resource manager */
699 ret = RMAllocResource(rm_drvh, ad_info->rm_bars + i, &resource);
700 if (ret != RMRC_SUCCESS) {
701 cprintf("error: couldn't register [MM]IO region (rc = %s)\n", rmerr(ret));
702 goto add_pci_fail;
703 }
704 rc_list->hResource[rc_list->NumResource++] = ad_info->rm_bars[i];
705 }
706
707 if (ad_info->mmio_phys == 0) {
708 cprintf("error: couldn't determine MMIO base address\n");
709 goto add_pci_fail;
710 }
711
712 /****************************************************************************
713 * Part 3: Fill in the remaining fields in the AD_INFO slot and allocate
714 * memory and GDT selectors for the adapter. Finally, register the adapter
715 * itself with the OS/2 resource manager
716 */
717 ad_info->pci = pci_ids + i;
718 ad_info->bus = bus;
719 ad_info->dev_func = dev_func;
720 ad_info->irq = irq;
721
722 /* allocate memory for port-specific DMA scratch buffers */
723 if (DevHelp_AllocPhys((long) AHCI_PORT_PRIV_DMA_SZ * AHCI_MAX_PORTS,
724 MEMTYPE_ABOVE_1M, &ad_info->dma_buf_phys) != 0) {
725 cprintf("error: couldn't allocate DMA scratch buffers for AHCI ports\n");
726 ad_info->dma_buf_phys = 0;
727 goto add_pci_fail;
728 }
729
730 /* allocate GDT selectors for memory-mapped I/O and DMA scratch buffers */
731 if (DevHelp_AllocGDTSelector(gdt, PORT_DMA_BUF_SEGS + 1) != 0) {
732 cprintf("error: couldn't allocate GDT selectors\n");
733 memset(gdt, 0x00, sizeof(gdt));
734 goto add_pci_fail;
735 }
736
737 /* map MMIO address to first GDT selector */
738 if (DevHelp_PhysToGDTSelector(ad_info->mmio_phys,
739 (USHORT) ad_info->mmio_size, gdt[0]) != 0) {
740 cprintf("error: couldn't map MMIO address to GDT selector\n");
741 goto add_pci_fail;
742 }
743
744 /* map DMA scratch buffers to remaining GDT selectors */
745 for (i = 0; i < PORT_DMA_BUF_SEGS; i++) {
746 ULONG addr = ad_info->dma_buf_phys + i * PORT_DMA_SEG_SIZE;
747 USHORT len = AHCI_PORT_PRIV_DMA_SZ * PORT_DMA_BUFS_PER_SEG;
748
749 if (DevHelp_PhysToGDTSelector(addr, len, gdt[i+1]) != 0) {
750 cprintf("error: couldn't map DMA scratch buffer to GDT selector\n");
751 goto add_pci_fail;
752 }
753 }
754
755 /* fill in MMIO and DMA scratch buffer addresses in adapter info */
756 ad_info->mmio = (u8 _far *) ((u32) gdt[0] << 16);
757 for (i = 0; i < PORT_DMA_BUF_SEGS; i++) {
758 ad_info->dma_buf[i] = (u8 _far *) ((u32) gdt[i+1] << 16);
759 }
760
761 /* register adapter with resource manager */
762 memset(&adj, 0x00, sizeof(adj));
763 adj.pNextAdj = NULL;
764 adj.AdjLength = sizeof(adj);
765 adj.AdjType = ADJ_ADAPTER_NUMBER;
766 adj.Adapter_Number = ad_info_cnt;
767
768 memset(&adapter, 0x00, sizeof(adapter));
769 sprintf(tmp, "AHCI_%d Controller", ad_info_cnt);
770 adapter.AdaptDescriptName = tmp;
771 adapter.AdaptFlags = 0;
772 adapter.BaseType = AS_BASE_MSD;
773 adapter.SubType = AS_SUB_IDE;
774 adapter.InterfaceType = AS_INTF_GENERIC;
775 adapter.HostBusType = AS_HOSTBUS_PCI;
776 adapter.HostBusWidth = AS_BUSWIDTH_32BIT;
777 adapter.pAdjunctList = &adj;
778
779 ret = RMCreateAdapter(rm_drvh, &ad_info->rm_adh, &adapter, NULL, rc_list);
780 if (ret != RMRC_SUCCESS) {
781 cprintf("error: couldn't register adapter (rc = %s)\n", rmerr(ret));
782 goto add_pci_fail;
783 }
784
785 /* Successfully added the adapter and reserved its resources; the adapter
786 * is still under BIOS control so we're not going to do anything else at
787 * this point.
788 */
789 ad_info_cnt++;
790 return;
791
792add_pci_fail:
793 /* something went wrong; try to clean up as far as possible */
794 for (i = 0; i < sizeof(ad_info->rm_bars) / sizeof(*ad_info->rm_bars); i++) {
795 if (ad_info->rm_bars[i] != 0) {
796 RMDeallocResource(rm_drvh, ad_info->rm_bars[i]);
797 }
798 }
799 if (ad_info->rm_irq != 0) {
800 RMDeallocResource(rm_drvh, ad_info->rm_irq);
801 }
802 for (i = 0; i < sizeof(gdt) / sizeof(*gdt); i++) {
803 if (gdt[i] != 0) {
804 DevHelp_FreeGDTSelector(gdt[i]);
805 }
806 }
807 if (ad_info->dma_buf_phys != 0) {
808 DevHelp_FreePhys(ad_info->dma_buf_phys);
809 }
810}
811
812/******************************************************************************
813 * Read PCI configuration space register
814 */
815static UCHAR pci_read_conf(UCHAR bus, UCHAR dev_func, UCHAR indx, UCHAR size,
816 ULONG _far *val)
817{
818 OH_PARM parm;
819 OH_DATA data;
820 UCHAR rc;
821
822 memset(&parm, 0x00, sizeof(parm));
823 parm.read_config.bus = bus;
824 parm.read_config.dev_func = dev_func;
825 parm.read_config.reg = indx;
826 parm.read_config.size = size;
827 if ((rc = oemhlp_call(OH_READ_CONFIG, &parm, &data) != OH_SUCCESS)) {
828 cprintf("error: couldn't read config space (bus = %d, dev_func = 0x%02x, indx = 0x%02x, rc = %d)\n",
829 bus, dev_func, indx, rc);
830 return(rc);
831 }
832
833 *val = data.read_config.data;
834 return(OH_SUCCESS);
835}
836
837/******************************************************************************
838 * Write PCI configuration space register
839 */
840static UCHAR pci_write_conf(UCHAR bus, UCHAR dev_func, UCHAR indx, UCHAR size,
841 ULONG val)
842{
843 OH_PARM parm;
844 OH_DATA data;
845 UCHAR rc;
846
847 memset(&parm, 0x00, sizeof(parm));
848 parm.write_config.bus = bus;
849 parm.write_config.dev_func = dev_func;
850 parm.write_config.reg = indx;
851 parm.write_config.size = size;
852 parm.write_config.data = val;
853
854 if ((rc = oemhlp_call(OH_WRITE_CONFIG, &parm, &data) != OH_SUCCESS)) {
855 cprintf("error: couldn't write config space (bus = %d, dev_func = 0x%02x, indx = 0x%02x, rc = %d)\n",
856 bus, dev_func, indx, rc);
857 return(rc);
858 }
859
860 return(OH_SUCCESS);
861}
862/******************************************************************************
863 * Call OEMHLP$ IDC entry point with the specified IOCtl parameter and data
864 * packets.
865 */
866static int oemhlp_call(UCHAR subfunction, OH_PARM _far *parm,
867 OH_DATA _far *data)
868{
869 void (_far *func)(void);
870 RP_GENIOCTL ioctl;
871 unsigned short prot_idc_ds;
872
873 if (oemhlp.ProtIDCEntry == NULL || oemhlp.ProtIDC_DS == 0) {
874 /* attach to OEMHLP$ device driver */
875 if (DevHelp_AttachDD("OEMHLP$ ", (NPBYTE) &oemhlp) ||
876 oemhlp.ProtIDCEntry == NULL ||
877 oemhlp.ProtIDC_DS == 0) {
878 cprintf("couldn't attach to OEMHLP$\n");
879 return(OH_NOT_SUPPORTED);
880 }
881 }
882
883 /* store subfuntion in first byte of pararameter packet */
884 parm->bios_info.subfunction = subfunction;
885 memset(data, 0x00, sizeof(*data));
886
887 /* assemble IOCtl request */
888 memset(&ioctl, 0x00, sizeof(ioctl));
889 ioctl.rph.Len = sizeof(ioctl);
890 ioctl.rph.Unit = 0;
891 ioctl.rph.Cmd = GENERIC_IOCTL;
892 ioctl.rph.Status = 0;
893
894 ioctl.Category = OH_CATEGORY;
895 ioctl.Function = OH_FUNC_PCI;
896 ioctl.ParmPacket = (PUCHAR) parm;
897 ioctl.DataPacket = (PUCHAR) data;
898 ioctl.ParmLen = sizeof(*parm);
899 ioctl.DataLen = sizeof(*data);
900
901 /* Call OEMHLP's IDC routine. Before doing so, we need to assign the address
902 * to be called to a stack variable because the inter-device driver calling
903 * convention forces us to set DS to the device driver's data segment and ES
904 * to the segment of the request packet.
905 */
906 func = oemhlp.ProtIDCEntry;
907
908 /* The WATCOM compiler does not support struct references in inline
909 * assembler code, so we pass it in a stack variable
910 */
911 prot_idc_ds = oemhlp.ProtIDC_DS;
912
913 _asm {
914 push ds;
915 push es;
916 push bx;
917 push si;
918 push di;
919
920 push ss
921 pop es
922 lea bx, ioctl;
923 mov ds, prot_idc_ds;
924 call dword ptr [func];
925
926 pop di;
927 pop si;
928 pop bx;
929 pop es;
930 pop ds;
931 }
932
933 dddphex(parm, sizeof(*parm), "oemhlp_parm: ");
934 dddphex(data, sizeof(*data), "oemhlp_data: ");
935
936 if (ioctl.rph.Status & STERR) {
937 return(OH_NOT_SUPPORTED);
938 }
939 return(data->bios_info.rc);
940}
941
942/******************************************************************************
943 * Prepare a resource structure for a PCI Base Address Register (BAR). This
944 * basically means the type, address and range of the I/O address space. It
945 * returns the length of the address range as a signed long to allow the caller
946 * to differentiate between error conditions (< 0), unused BARs (0) or valid
947 * bars (> 0).
948 *
949 * NOTE: In order to do this, we need to temporarily write 0xffffffff to
950 * the MMIO base address register (BAR), read back the resulting value
951 * and check the 0 bits from the right end, masking the lower 2 (I/O) or
952 * 4 (MMIO) bits. After doing this, we must restore the original value
953 * set up by the BIOS.
954 *
955 * 31 4 3 2 1 0
956 * -------------------------------------------------------------------
957 * base address P T T I
958 * P = prefetchable
959 * T = type (0 = any 32 bit, 1 = <1M, 2 = 64 bit)
960 * I = I/O (1) or memory (0)
961 */
962static long bar_resource(UCHAR bus, UCHAR dev_func,
963 RESOURCESTRUCT _far *resource, int i)
964{
965 u32 bar_addr = 0;
966 u32 bar_size = 0;
967
968 /* temporarily write 1s to this BAR to determine the address range */
969 if (pci_read_conf (bus, dev_func, PCI_BAR(i), sizeof(u32), &bar_addr) != OH_SUCCESS ||
970 pci_write_conf(bus, dev_func, PCI_BAR(i), sizeof(u32), ~(0UL)) != OH_SUCCESS ||
971 pci_read_conf (bus, dev_func, PCI_BAR(i), sizeof(u32), &bar_size) != OH_SUCCESS ||
972 pci_write_conf(bus, dev_func, PCI_BAR(i), sizeof(u32), bar_addr) != OH_SUCCESS) {
973
974 cprintf("error: couldn't determine [MM]IO size\n");
975 if (bar_addr != 0) {
976 pci_write_conf(bus, dev_func, PCI_BAR(i), sizeof(u32), bar_addr);
977 }
978 return(-1);
979 }
980
981 if (bar_size == 0 || bar_size == 0xffffffffUL) {
982 /* bar not implemented or device not working properly */
983 return(0);
984 }
985
986 /* prepare resource allocation structure */
987 memset(resource, 0x00, sizeof(*resource));
988 if (bar_addr & 1) {
989 bar_size = ~(bar_size & 0xfffffffcUL) + 1;
990 bar_size &= 0xffffUL; /* I/O address space is 16 bits on x86 */
991 bar_addr &= 0xfffcUL;
992
993 resource->ResourceType = RS_TYPE_IO;
994 resource->IOResource.BaseIOPort = bar_addr;
995 resource->IOResource.NumIOPorts = bar_size;
996 resource->IOResource.IOFlags = RS_IO_EXCLUSIVE;
997 resource->IOResource.IOAddressLines = 16;
998
999 } else {
1000 bar_size = ~(bar_size & 0xfffffff0UL) + 1;
1001 bar_addr &= 0xfffffff0UL;
1002
1003 resource->ResourceType = RS_TYPE_MEM;
1004 resource->MEMResource.MemBase = bar_addr;
1005 resource->MEMResource.MemSize = bar_size;
1006 resource->MEMResource.MemFlags = RS_MEM_EXCLUSIVE;
1007 }
1008
1009 ddprintf("BAR #%d: type = %s, addr = 0x%08lx, size = %ld\n", i,
1010 (resource->ResourceType == RS_TYPE_IO) ? "I/O" : "MMIO",
1011 bar_addr, bar_size);
1012
1013 return((long) bar_size);
1014}
1015
1016/******************************************************************************
1017 * return vendor name for PCI vendor ID
1018 */
1019char *vendor_from_id(u16 id)
1020{
1021
1022 switch(id) {
1023
1024 case PCI_VENDOR_ID_AL:
1025 return "Ali";
1026 case PCI_VENDOR_ID_AMD:
1027 case PCI_VENDOR_ID_ATI:
1028 return "AMD";
1029 case PCI_VENDOR_ID_AT:
1030 return "Allied Telesyn";
1031 case PCI_VENDOR_ID_ATT:
1032 return "ATT";
1033 case PCI_VENDOR_ID_CMD:
1034 return "CMD";
1035 case PCI_VENDOR_ID_CT:
1036 return "CT";
1037 case PCI_VENDOR_ID_INTEL:
1038 return "Intel";
1039 case PCI_VENDOR_ID_INITIO:
1040 return "Initio";
1041 case PCI_VENDOR_ID_JMICRON:
1042 return "JMicron";
1043 case PCI_VENDOR_ID_MARVELL:
1044 return "Marvell";
1045 case PCI_VENDOR_ID_NVIDIA:
1046 return "NVIDIA";
1047 case PCI_VENDOR_ID_PROMISE:
1048 return "PROMISE";
1049 case PCI_VENDOR_ID_SI:
1050 return "SiS";
1051 case PCI_VENDOR_ID_VIA:
1052 return "VIA";
1053 default:
1054 break;
1055 }
1056
1057 return "Generic";
1058
1059}
1060
1061/******************************************************************************
1062 * return a device name for a PCI device id
1063 * NOTE: this is as simple as can be, so don't call it twice in one statement.
1064 */
1065char *device_from_id(u16 device)
1066{
1067 int i;
1068
1069 for (i = 0; pci_ids[i].vendor != 0; i++) {
1070
1071 if (pci_ids[i].device == device) {
1072 return pci_ids[i].chipname;
1073 }
1074
1075 }
1076
1077 return s_generic;
1078}
1079
1080/******************************************************************************
1081 * Return textual version of a resource manager error
1082 */
1083static char *rmerr(APIRET ret)
1084{
1085 switch (ret) {
1086 case RMRC_SUCCESS:
1087 return("RMRC_SUCCESS");
1088 case RMRC_NOTINITIALIZED:
1089 return("RMRC_NOTINITIALIZED");
1090 case RMRC_BAD_DRIVERHANDLE:
1091 return("RMRC_BAD_DRIVERHANDLE");
1092 case RMRC_BAD_ADAPTERHANDLE:
1093 return("RMRC_BAD_ADAPTERHANDLE");
1094 case RMRC_BAD_DEVICEHANDLE:
1095 return("RMRC_BAD_DEVICEHANDLE");
1096 case RMRC_BAD_RESOURCEHANDLE:
1097 return("RMRC_BAD_RESOURCEHANDLE");
1098 case RMRC_BAD_LDEVHANDLE:
1099 return("RMRC_BAD_LDEVHANDLE");
1100 case RMRC_BAD_SYSNAMEHANDLE:
1101 return("RMRC_BAD_SYSNAMEHANDLE");
1102 case RMRC_BAD_DEVHELP:
1103 return("RMRC_BAD_DEVHELP");
1104 case RMRC_NULL_POINTER:
1105 return("RMRC_NULL_POINTER");
1106 case RMRC_NULL_STRINGS:
1107 return("RMRC_NULL_STRINGS");
1108 case RMRC_BAD_VERSION:
1109 return("RMRC_BAD_VERSION");
1110 case RMRC_RES_ALREADY_CLAIMED:
1111 return("RMRC_RES_ALREADY_CLAIMED");
1112 case RMRC_DEV_ALREADY_CLAIMED:
1113 return("RMRC_DEV_ALREADY_CLAIMED");
1114 case RMRC_INVALID_PARM_VALUE:
1115 return("RMRC_INVALID_PARM_VALUE");
1116 case RMRC_OUT_OF_MEMORY:
1117 return("RMRC_OUT_OF_MEMORY");
1118 case RMRC_SEARCH_FAILED:
1119 return("RMRC_SEARCH_FAILED");
1120 case RMRC_BUFFER_TOO_SMALL:
1121 return("RMRC_BUFFER_TOO_SMALL");
1122 case RMRC_GENERAL_FAILURE:
1123 return("RMRC_GENERAL_FAILURE");
1124 case RMRC_IRQ_ENTRY_ILLEGAL:
1125 return("RMRC_IRQ_ENTRY_ILLEGAL");
1126 case RMRC_NOT_IMPLEMENTED:
1127 return("RMRC_NOT_IMPLEMENTED");
1128 case RMRC_NOT_INSTALLED:
1129 return("RMRC_NOT_INSTALLED");
1130 case RMRC_BAD_DETECTHANDLE:
1131 return("RMRC_BAD_DETECTHANDLE");
1132 case RMRC_BAD_RMHANDLE:
1133 return("RMRC_BAD_RMHANDLE");
1134 case RMRC_BAD_FLAGS:
1135 return("RMRC_BAD_FLAGS");
1136 case RMRC_NO_DETECTED_DATA:
1137 return("RMRC_NO_DETECTED_DATA");
1138 default:
1139 return("RMRC_UNKOWN");
1140 }
1141}
Note: See TracBrowser for help on using the repository browser.