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

Last change on this file since 174 was 174, checked in by David Azarewicz, 12 years ago

Fix for hardware that reports incorrect status.
Now report both real and fake devices when SCSI emulation is enabled.

File size: 43.4 KB
Line 
1/******************************************************************************
2 * PCI.c - PCI constants and detection code for os2ahci driver
3 *
4 * Copyright (c) 2011 thi.guten Software Development
5 * Copyright (c) 2011 Mensys B.V.
6 * Copyright (c) 2013 David Azarewicz
7 *
8 * Authors: Christian Mueller, Markus Thielen
9 *
10 * Parts copied from/inspired by the Linux AHCI driver;
11 * those parts are (c) Linux AHCI/ATA maintainers
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 */
27
28#include "os2ahci.h"
29
30/* -------------------------- macros and constants ------------------------- */
31
32/* offset of PCI base address register (BAR) in the PCI config space */
33#define PCI_BAR(reg) (UCHAR) (0x10 + (reg) * sizeof(u32))
34
35/******************************************************************************
36 * OEMHLP constants for PCI access
37 */
38#define GENERIC_IOCTL 0x10
39#define OH_CATEGORY 0x00
40#define OH_FUNC_PCI 0x0b
41
42/* subfunctions */
43#define OH_BIOS_INFO 0x00
44#define OH_FIND_DEVICE 0x01
45#define OH_FIND_CLASS 0x02
46#define OH_READ_CONFIG 0x03
47#define OH_WRITE_CONFIG 0x04
48
49/* return codes */
50#define OH_SUCCESS 0x00
51#define OH_NOT_SUPPORTED 0x81
52#define OH_BAD_VENDOR 0x83
53#define OH_NOT_FOUND 0x86
54#define OH_BAD_REGISTER 0x87
55
56/* ------------------------ typedefs and structures ------------------------ */
57
58/******************************************************************************
59 * OEMHLP IOCtl parameter union. The parameter area is generally used as input
60 * to the OEMHLP IOCtl calls.
61 */
62typedef union {
63
64 /* query PCI BIOS information" */
65 struct {
66 UCHAR subfunction;
67 } bios_info;
68
69 /* find PCI device */
70 struct {
71 UCHAR subfunction;
72 USHORT device;
73 USHORT vendor;
74 UCHAR index;
75 } find_device;
76
77 /* find PCI class code */
78 struct {
79 UCHAR subfunction;
80 ULONG class;
81 UCHAR index;
82 } find_class;
83
84 /* read PCI configuration space */
85 struct {
86 UCHAR subfunction;
87 UCHAR bus;
88 UCHAR dev_func;
89 UCHAR reg;
90 UCHAR size;
91 } read_config;
92
93 /* write PCI configuration space */
94 struct {
95 UCHAR subfunction;
96 UCHAR bus;
97 UCHAR dev_func;
98 UCHAR reg;
99 UCHAR size;
100 ULONG data;
101 } write_config;
102
103} OH_PARM;
104
105/******************************************************************************
106 * OEMHLP IOCtl data union. The data area is generally used as output from the
107 * OEMHLP IOCtl calls.
108 */
109typedef union {
110
111 /* query PCI BIOS information" */
112 struct {
113 UCHAR rc;
114 UCHAR hw_mech;
115 UCHAR major_version;
116 UCHAR minor_version;
117 UCHAR last_bus;
118 } bios_info;
119
120 /* find PCI device */
121 struct {
122 UCHAR rc;
123 UCHAR bus;
124 UCHAR dev_func;
125 } find_device;
126
127 /* find PCI class code */
128 struct {
129 UCHAR rc;
130 UCHAR bus;
131 UCHAR dev_func;
132 } find_class;
133
134 /* read PCI confguration space */
135 struct {
136 UCHAR rc;
137 ULONG data;
138 } read_config;
139
140 /* write PCI confguration space */
141 struct {
142 UCHAR rc;
143 } write_config;
144
145} OH_DATA;
146
147/* -------------------------- function prototypes -------------------------- */
148
149static void add_pci_device (PCI_ID *pci_id, OH_DATA _far *data);
150static int oemhlp_call (UCHAR subfunction, OH_PARM _far *parm,
151 OH_DATA _far *data);
152static long bar_resource (UCHAR bus, UCHAR dev_func,
153 RESOURCESTRUCT _far *resource, int i);
154static char *rmerr (APIRET ret);
155
156/* ------------------------ global/static variables ------------------------ */
157
158/******************************************************************************
159 * chipset/controller name strings
160 */
161static char chip_esb2[] = "ESB2";
162static char chip_ich8[] = "ICH8";
163static char chip_ich8m[] = "ICH8M";
164static char chip_ich9[] = "ICH9";
165static char chip_ich9m[] = "ICH9M";
166static char chip_ich10[] = "ICH10";
167static char chip_pchahci[] = "PCH AHCI";
168static char chip_pchraid[] = "PCH RAID";
169static char chip_tolapai[] = "Tolapai";
170static char chip_sb600[] = "SB600";
171static char chip_sb700[] = "SB700/800";
172static char chip_vt8251[] = "VT8251";
173static char chip_mcp65[] = "MCP65";
174static char chip_mcp67[] = "MCP67";
175static char chip_mcp73[] = "MCP73";
176static char chip_mcp77[] = "MCP77";
177static char chip_mcp79[] = "MCP79";
178static char chip_mcp89[] = "MCP689";
179static char chip_sis968[] = "968";
180
181static char s_generic[] = "Generic";
182
183
184
185/******************************************************************************
186 * PCI vendor and device IDs for known AHCI adapters. Copied from the Linux
187 * AHCI driver.
188 */
189
190PCI_ID pci_ids[] = {
191
192 /* Intel
193 * NOTE: ICH5 controller does NOT support AHCI, so we do
194 * not add it here! */
195 { PCI_VDEVICE(INTEL, 0x2652), board_ahci, "ICH6" }, /* ICH6 */
196 { PCI_VDEVICE(INTEL, 0x2653), board_ahci, "ICH6M" }, /* ICH6M */
197 { PCI_VDEVICE(INTEL, 0x27c1), board_ahci, "ICH7" }, /* ICH7 */
198 { PCI_VDEVICE(INTEL, 0x27c5), board_ahci, "ICH7M" }, /* ICH7M */
199 { PCI_VDEVICE(INTEL, 0x27c3), board_ahci, "ICH7R" }, /* ICH7R */
200 { PCI_VDEVICE(AL, 0x5288), board_ahci_ign_iferr, "ULiM5288" }, /* ULi M5288 */
201 { PCI_VDEVICE(INTEL, 0x2681), board_ahci, chip_esb2 }, /* ESB2 */
202 { PCI_VDEVICE(INTEL, 0x2682), board_ahci, chip_esb2 }, /* ESB2 */
203 { PCI_VDEVICE(INTEL, 0x2683), board_ahci, chip_esb2 }, /* ESB2 */
204 { PCI_VDEVICE(INTEL, 0x27c6), board_ahci, "ICH7MDH" }, /* ICH7-M DH */
205 { PCI_VDEVICE(INTEL, 0x2821), board_ahci, chip_ich8 }, /* ICH8 */
206 { PCI_VDEVICE(INTEL, 0x2822), board_ahci_nosntf, chip_ich8 }, /* ICH8 */
207 { PCI_VDEVICE(INTEL, 0x2824), board_ahci, chip_ich8 }, /* ICH8 */
208 { PCI_VDEVICE(INTEL, 0x2829), board_ahci, chip_ich8m }, /* ICH8M */
209 { PCI_VDEVICE(INTEL, 0x282a), board_ahci, chip_ich8m }, /* ICH8M */
210 { PCI_VDEVICE(INTEL, 0x2922), board_ahci, chip_ich9 }, /* ICH9 */
211 { PCI_VDEVICE(INTEL, 0x2923), board_ahci, chip_ich9 }, /* ICH9 */
212 { PCI_VDEVICE(INTEL, 0x2924), board_ahci, chip_ich9 }, /* ICH9 */
213 { PCI_VDEVICE(INTEL, 0x2925), board_ahci, chip_ich9 }, /* ICH9 */
214 { PCI_VDEVICE(INTEL, 0x2927), board_ahci, chip_ich9 }, /* ICH9 */
215 { PCI_VDEVICE(INTEL, 0x2929), board_ahci, chip_ich9m }, /* ICH9M */
216 { PCI_VDEVICE(INTEL, 0x292a), board_ahci, chip_ich9m }, /* ICH9M */
217 { PCI_VDEVICE(INTEL, 0x292b), board_ahci, chip_ich9m }, /* ICH9M */
218 { PCI_VDEVICE(INTEL, 0x292c), board_ahci, chip_ich9m }, /* ICH9M */
219 { PCI_VDEVICE(INTEL, 0x292f), board_ahci, chip_ich9m }, /* ICH9M */
220 { PCI_VDEVICE(INTEL, 0x294d), board_ahci, chip_ich9 }, /* ICH9 */
221 { PCI_VDEVICE(INTEL, 0x294e), board_ahci, chip_ich9m }, /* ICH9M */
222 { PCI_VDEVICE(INTEL, 0x502a), board_ahci, chip_tolapai }, /* Tolapai */
223 { PCI_VDEVICE(INTEL, 0x502b), board_ahci, chip_tolapai }, /* Tolapai */
224 { PCI_VDEVICE(INTEL, 0x3a05), board_ahci, chip_ich10 }, /* ICH10 */
225 { PCI_VDEVICE(INTEL, 0x3a22), board_ahci, chip_ich10 }, /* ICH10 */
226 { PCI_VDEVICE(INTEL, 0x3a25), board_ahci, chip_ich10 }, /* ICH10 */
227 { PCI_VDEVICE(INTEL, 0x3b22), board_ahci, chip_pchahci }, /* PCH AHCI */
228 { PCI_VDEVICE(INTEL, 0x3b23), board_ahci, chip_pchahci }, /* PCH AHCI */
229 { PCI_VDEVICE(INTEL, 0x3b24), board_ahci, chip_pchraid }, /* PCH RAID */
230 { PCI_VDEVICE(INTEL, 0x3b25), board_ahci, chip_pchraid }, /* PCH RAID */
231 { PCI_VDEVICE(INTEL, 0x3b29), board_ahci, chip_pchahci }, /* PCH AHCI */
232 { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci, chip_pchraid }, /* PCH RAID */
233 { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci, chip_pchraid }, /* PCH RAID */
234 { PCI_VDEVICE(INTEL, 0x3b2f), board_ahci, chip_pchahci }, /* PCH AHCI */
235
236 /* JMicron 360/1/3/5/6, match class to avoid IDE function */
237 { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
238 PCI_CLASS_STORAGE_SATA_AHCI, 0xffffffL, board_ahci_ign_iferr, "360" },
239
240 /* ATI */
241 { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600, chip_sb600 }, /* ATI SB600 */
242 { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
243 { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
244 { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
245 { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
246 { PCI_VDEVICE(ATI, 0x4394), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
247 { PCI_VDEVICE(ATI, 0x4395), board_ahci_sb700, chip_sb700 }, /* ATI SB700/800 */
248
249 /* AMD */
250 { PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD Hudson-2 */
251 /* AMD is using RAID class only for ahci controllers */
252 { PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
253 PCI_CLASS_STORAGE_RAID << 8, 0xffffffL, board_ahci, "Hudson2" },
254
255 /* VIA */
256 { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251, chip_vt8251 }, /* VIA VT8251 */
257 { PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251, chip_vt8251 }, /* VIA VT8251 */
258
259 /* NVIDIA */
260 { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
261 { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
262 { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
263 { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
264 { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
265 { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
266 { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
267 { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65, chip_mcp65 }, /* MCP65 */
268 { PCI_VDEVICE(NVIDIA, 0x0550), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
269 { PCI_VDEVICE(NVIDIA, 0x0551), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
270 { PCI_VDEVICE(NVIDIA, 0x0552), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
271 { PCI_VDEVICE(NVIDIA, 0x0553), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
272 { PCI_VDEVICE(NVIDIA, 0x0554), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
273 { PCI_VDEVICE(NVIDIA, 0x0555), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
274 { PCI_VDEVICE(NVIDIA, 0x0556), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
275 { PCI_VDEVICE(NVIDIA, 0x0557), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
276 { PCI_VDEVICE(NVIDIA, 0x0558), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
277 { PCI_VDEVICE(NVIDIA, 0x0559), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
278 { PCI_VDEVICE(NVIDIA, 0x055a), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
279 { PCI_VDEVICE(NVIDIA, 0x055b), board_ahci_yesncq, chip_mcp67 }, /* MCP67 */
280 { PCI_VDEVICE(NVIDIA, 0x0580), board_ahci_yesncq, chip_mcp67 }, /* Linux ID */
281 { PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
282 { PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
283 { PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
284 { PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
285 { PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
286 { PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
287 { PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
288 { PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
289 { PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
290 { PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
291 { PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
292 { PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci_yesncq, chip_mcp73 }, /* MCP73 */
293 { PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci, chip_mcp77 }, /* MCP77 */
294 { PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci, chip_mcp77 }, /* MCP77 */
295 { PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci, chip_mcp77 }, /* MCP77 */
296 { PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci, chip_mcp77 }, /* MCP77 */
297 { PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci, chip_mcp77 }, /* MCP77 */
298 { PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci, chip_mcp77 }, /* MCP77 */
299 { PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci, chip_mcp77 }, /* MCP77 */
300 { PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci, chip_mcp77 }, /* MCP77 */
301 { PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci, chip_mcp77 }, /* MCP77 */
302 { PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci, chip_mcp77 }, /* MCP77 */
303 { PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci, chip_mcp77 }, /* MCP77 */
304 { PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci, chip_mcp77 }, /* MCP77 */
305 { PCI_VDEVICE(NVIDIA, 0x0ab4), board_ahci, chip_mcp79 }, /* MCP79 */
306 { PCI_VDEVICE(NVIDIA, 0x0ab5), board_ahci, chip_mcp79 }, /* MCP79 */
307 { PCI_VDEVICE(NVIDIA, 0x0ab6), board_ahci, chip_mcp79 }, /* MCP79 */
308 { PCI_VDEVICE(NVIDIA, 0x0ab7), board_ahci, chip_mcp79 }, /* MCP79 */
309 { PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci, chip_mcp79 }, /* MCP79 */
310 { PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci, chip_mcp79 }, /* MCP79 */
311 { PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci, chip_mcp79 }, /* MCP79 */
312 { PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci, chip_mcp79 }, /* MCP79 */
313 { PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci, chip_mcp79 }, /* MCP79 */
314 { PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci, chip_mcp79 }, /* MCP79 */
315 { PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci, chip_mcp79 }, /* MCP79 */
316 { PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci, chip_mcp79 }, /* MCP79 */
317 { PCI_VDEVICE(NVIDIA, 0x0d84), board_ahci, chip_mcp89 }, /* MCP89 */
318 { PCI_VDEVICE(NVIDIA, 0x0d85), board_ahci, chip_mcp89 }, /* MCP89 */
319 { PCI_VDEVICE(NVIDIA, 0x0d86), board_ahci, chip_mcp89 }, /* MCP89 */
320 { PCI_VDEVICE(NVIDIA, 0x0d87), board_ahci, chip_mcp89 }, /* MCP89 */
321 { PCI_VDEVICE(NVIDIA, 0x0d88), board_ahci, chip_mcp89 }, /* MCP89 */
322 { PCI_VDEVICE(NVIDIA, 0x0d89), board_ahci, chip_mcp89 }, /* MCP89 */
323 { PCI_VDEVICE(NVIDIA, 0x0d8a), board_ahci, chip_mcp89 }, /* MCP89 */
324 { PCI_VDEVICE(NVIDIA, 0x0d8b), board_ahci, chip_mcp89 }, /* MCP89 */
325 { PCI_VDEVICE(NVIDIA, 0x0d8c), board_ahci, chip_mcp89 }, /* MCP89 */
326 { PCI_VDEVICE(NVIDIA, 0x0d8d), board_ahci, chip_mcp89 }, /* MCP89 */
327 { PCI_VDEVICE(NVIDIA, 0x0d8e), board_ahci, chip_mcp89 }, /* MCP89 */
328 { PCI_VDEVICE(NVIDIA, 0x0d8f), board_ahci, chip_mcp89 }, /* MCP89 */
329
330 /* SiS */
331 { PCI_VDEVICE(SI, 0x1184), board_ahci, "966" }, /* SiS 966 */
332 { PCI_VDEVICE(SI, 0x1185), board_ahci, chip_sis968 }, /* SiS 968 */
333 { PCI_VDEVICE(SI, 0x0186), board_ahci, chip_sis968 }, /* SiS 968 */
334
335 /* Marvell */
336 { PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv, "6145" }, /* 6145 */
337 { PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv, "6121" }, /* 6121 */
338
339 /* Promise */
340 { PCI_VDEVICE(PROMISE, 0x3f20), board_ahci, "PDC42819" }, /* PDC42819 */
341
342 /* Generic, PCI class code for AHCI */
343 { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
344 PCI_CLASS_STORAGE_SATA_AHCI, 0xffffffL, board_ahci, s_generic },
345
346 /* end of list, including a few slots to define custom adapters (10) */
347 { 0, 0, 0, 0, 0, 0, 0, NULL },
348 { 0, 0, 0, 0, 0, 0, 0, NULL },
349 { 0, 0, 0, 0, 0, 0, 0, NULL },
350 { 0, 0, 0, 0, 0, 0, 0, NULL },
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
358 { 0, 0, 0, 0, 0, 0, 0, NULL }
359};
360
361/******************************************************************************
362 * OEMHLP$ is used by OS/2 to provide access to OEM-specific machine resources
363 * like PCI BIOS access. We're using this to enumerate the PCI bus. Due to
364 * BIOS bugs, it may be necessary to use I/O operations for this purpose but
365 * so far I think this is only relevant for rather old PCs and SATA is not
366 * expected to be a priority on those machines.
367 */
368static IDCTABLE oemhlp; /* OEMHLP$ IDC entry point */
369
370/* ----------------------------- start of code ----------------------------- */
371
372/******************************************************************************
373 * Add specified PCI vendor and device ID to the list of supported AHCI
374 * controllers. Please note that the last slot in pci_ids needs to remain
375 * empty because it's used as end marker.
376 */
377int add_pci_id(u16 vendor, u16 device)
378{
379 int max_slot = sizeof(pci_ids) / sizeof(*pci_ids) - 2;
380 int i;
381
382 /* search for last used slot in 'pci_ids' */
383 for (i = max_slot; i >= 0 && pci_ids[i].vendor == 0; i--);
384 if (i >= max_slot) {
385 /* all slots in use */
386 return(-1);
387 }
388
389 /* use slot after the last used slot */
390 i++;
391 pci_ids[i].vendor = vendor;
392 pci_ids[i].device = device;
393 pci_ids[i].board = board_ahci;
394 pci_ids[i].chipname = s_generic;
395 return(0);
396}
397
398/******************************************************************************
399 * Scan PCI bus using OEMHLP$ IOCTLs and build adapter list.
400 */
401void scan_pci_bus(void)
402{
403 OH_PARM parm;
404 OH_DATA data;
405 UCHAR index;
406 UCHAR rc;
407 int ad_indx = 0;
408 int i;
409 int n;
410
411 ddprintf("scanning PCI bus...\n");
412
413 /* verify that we have a PCI system */
414 memset(&parm, 0x00, sizeof(parm));
415 if (oemhlp_call(OH_BIOS_INFO, &parm, &data) != OH_SUCCESS) {
416 cprintf("%s: couldn't get PCI BIOS information\n", drv_name);
417 return;
418 }
419
420 /* Go through the list of PCI IDs and search for each device
421 *
422 * NOTES:
423 *
424 * - When searching via class code, the OEMHLP$ interface doesn't allow
425 * setting a bitmask to look for individual portions of class code,
426 * subclass code and programming interface. However, all bitmasks in the
427 * PCI list currently use 0xffffff, thus this should not be a problem at
428 * this point in time.
429 *
430 * - Scanning via OEMHLP$ seems rather slow, at least in the virtual
431 * machine I'm currenly using to test this driver. Thus, class code
432 * scans are preferred unless the option "-t" (thorough_scan) has been
433 * specified. The assumption is that most, if not all, modern AHCI
434 * adapters have the correct class code (PCI_CLASS_STORAGE_SATA_AHCI).
435 */
436 for (i = 0; pci_ids[i].vendor != 0; i++) {
437 index = 0;
438 do {
439 if (pci_ids[i].device == PCI_ANY_ID || pci_ids[i].vendor == PCI_ANY_ID) {
440 /* look for class code */
441 memset(&parm, 0x00, sizeof(parm));
442 parm.find_class.class = pci_ids[i].class;
443 parm.find_class.index = index;
444 rc = oemhlp_call(OH_FIND_CLASS, &parm, &data);
445
446 } else if (thorough_scan) {
447 /* look for this specific vendor and device ID */
448 memset(&parm, 0x00, sizeof(parm));
449 parm.find_device.device = pci_ids[i].device;
450 parm.find_device.vendor = pci_ids[i].vendor;
451 parm.find_device.index = index;
452 rc = oemhlp_call(OH_FIND_DEVICE, &parm, &data);
453
454 } else {
455 rc = OH_NOT_FOUND;
456 }
457
458 if (rc == OH_SUCCESS) {
459 /* found a device */
460 int already_found = 0;
461
462 /* increment index for next loop */
463 if (++index > 180) {
464 /* something's wrong here... */
465 return;
466 }
467
468 /* check whether we already found this device */
469 for (n = 0; n < ad_info_cnt; n++) {
470 if (ad_infos[n].bus == data.find_device.bus &&
471 ad_infos[n].dev_func == data.find_device.dev_func) {
472 /* this device has already been found (e.g. via thorough scan) */
473 already_found = 1;
474 break;
475 }
476 }
477
478 if (already_found || (ad_ignore & (1U << ad_indx++))) {
479 /* ignore this device; it has either already been found via a
480 * thorough scan or has been specified to be ignored via command
481 * line option */
482 continue;
483 }
484
485 /* add this PCI device to ad_infos[] */
486 add_pci_device(pci_ids + i, &data);
487 }
488
489 } while (rc == OH_SUCCESS);
490 }
491}
492
493/******************************************************************************
494 * Enable interrupt generation. PCI 2.3 added a bit which allows disabling
495 * interrupt generation for a device. This function clears the corresponding
496 * bit in the configuration space command register.
497 */
498int pci_enable_int(UCHAR bus, UCHAR dev_func)
499{
500 ULONG tmp;
501
502 if (pci_read_conf (bus, dev_func, 4, sizeof(u32), &tmp) != OH_SUCCESS ||
503 pci_write_conf(bus, dev_func, 4, sizeof(u32), tmp & ~(1UL << 10)) != OH_SUCCESS) {
504 return(-1);
505 }
506 return(0);
507}
508
509/******************************************************************************
510 * Hack to set up proper IRQ mappings in the emulated PIIX3 ISA bridge in
511 * VirtualBox (for some reason, the first mapped IRQ is 0x80 without this
512 * hack).
513 */
514void pci_hack_virtualbox(void)
515{
516 ULONG irq = 0;
517
518 if (pci_read_conf(0, 0x08, 0x60, 1, &irq) == OH_SUCCESS && irq == 0x80) {
519 /* set IRQ for first device/func to 11 */
520 dprintf("hacking virtualbox PIIX3 PCI to ISA bridge IRQ mapping\n");
521 irq = ad_infos[0].irq;
522 pci_write_conf(0, 0x08, 0x60, 1, irq);
523 }
524}
525
526/******************************************************************************
527 * Add a single PCI device to the list of adapters.
528 */
529static void add_pci_device(PCI_ID *pci_id, OH_DATA _far *data)
530{
531 char rc_list_buf[sizeof(AHRESOURCE) + sizeof(HRESOURCE) * 15];
532 AHRESOURCE _far *rc_list = (AHRESOURCE _far *) rc_list_buf;
533 RESOURCESTRUCT resource;
534 ADAPTERSTRUCT adapter;
535 ADJUNCT adj;
536 AD_INFO *ad_info;
537 APIRET ret;
538 UCHAR bus = data->find_class.bus;
539 UCHAR dev_func = data->find_class.dev_func;
540 ULONG val;
541 SEL gdt[PORT_DMA_BUF_SEGS + 1];
542 char tmp[40];
543 u16 device;
544 u16 vendor;
545 u32 class;
546 int irq;
547 int pin;
548 int i;
549
550 /*****************************************************************************
551 * Part 1: Get further information about the device to be added; PCI ID...
552 */
553 if (pci_read_conf(bus, dev_func, 0x00, sizeof(ULONG), &val) != OH_SUCCESS) {
554 return;
555 }
556 device = (u16) (val >> 16);
557 vendor = (u16) (val & 0xffff);
558
559 /* ... and class code */
560 if (pci_read_conf(bus, dev_func, 0x08, sizeof(ULONG), &val) != OH_SUCCESS) {
561 return;
562 }
563 class = (u32) (val >> 8);
564
565 if (pci_id->device == PCI_ANY_ID) {
566 /* We found this device in a wildcard search. There are two possible
567 * reasons which require a different handling:
568 *
569 * 1) This device uses a non-standard PCI class and has been identified
570 * with the corresponding class in pci_ids[] (e.g. the entry
571 * PCI_VENDOR_ID_JMICRON), but there is a vendor ID in pci_ids[]. In
572 * this case, we need to verify that the vendor is correct (see
573 * comments regarding OEMHLP limitations in 'scan_pci_bus()')
574 *
575 * 2) This device was identified using a generic PCI class for AHCI
576 * adapters such as PCI_CLASS_STORAGE_SATA_AHCI and we need to map
577 * the device and vendor ID to the corresponding index in pci_ids[]
578 * if there is such an entry; the index passed to this function will
579 * be the generic class-based index which is fine as long as there's
580 * not special treatment required as indicated by the board_*
581 * constants in pci_ids[]...
582 *
583 * The main reason for this kludge is that it seems as if OEMHLP$
584 * is rather slow searching for PCI devices, adding around 30s
585 * to the boot time when scanning for individual AHCI PCI IDs. Thus,
586 * the OS2AHCI driver avoids this kind of scan in favor of a class-
587 * based scan (unless overridden with the "/T" option).
588 */
589 if (pci_id->vendor != PCI_ANY_ID) {
590 /* case 1: the vendor is known but we found the PCI device using a class
591 * search; verify vendor matches the one in pci_ids[]
592 */
593 if (pci_id->vendor != vendor) {
594 /* vendor doesn't match */
595 return;
596 }
597
598 } else {
599 /* case 2: we found this device using a generic class search; if the
600 * device/vendor is listed in pci_ids[], use this entry in favor of the
601 * one passed in 'pci_id'
602 */
603 for (i = 0; pci_ids[i].vendor != 0; i++) {
604 if (pci_ids[i].device == device && pci_ids[i].vendor == vendor) {
605 pci_id = pci_ids + i;
606 break;
607 }
608 }
609 }
610 }
611
612 /* found a supported AHCI device */
613 ciiprintf("Found AHCI device %s %s (%d:%d:%d %04x:%04x) class:0x%06lx\n",
614 vendor_from_id(vendor), device_from_id(device),
615 bus, dev_func>>3, dev_func&7, vendor, device, class);
616
617 /* make sure we got room in the adapter information array */
618 if (ad_info_cnt >= MAX_AD - 1) {
619 cprintf("%s: too many AHCI devices\n", drv_name);
620 return;
621 }
622
623 /****************************************************************************
624 * Part 2: Determine resource requirements and allocate resources with the
625 * OS/2 resource manager. While doing so, some of the entries of the
626 * corresponding slot in the AD_INFO array, namely resource manager
627 * handles, are initialized so we need prepare the slot.
628 *
629 * NOTE: While registering resources with the resource manager, each new
630 * resource is added to the corresponding rc_list.hResource[] slot.
631 * rc_list is used further down to associate resources to adapters
632 * when the adapter itself is registered with the OS/2 resource
633 * manager.
634 */
635 ad_info = ad_infos + ad_info_cnt;
636 memset(ad_info, 0x00, sizeof(*ad_info));
637 rc_list->NumResource = 0;
638
639 /* Register IRQ with resource manager
640 *
641 * NOTE: We rely on the IRQ number saved in the PCI config space by the PCI
642 * BIOS. There's no reliable way to find out the IRQ number in any
643 * other way unless we start using message-driven interrupts (which
644 * is out of scope for the time being).
645 */
646 if (pci_read_conf(bus, dev_func, 0x3c, sizeof(u32), &val) != OH_SUCCESS) {
647 return;
648 }
649 irq = (int) (val & 0xff);
650 pin = (int) ((val >> 8) & 0xff);
651
652 memset(&resource, 0x00, sizeof(resource));
653 resource.ResourceType = RS_TYPE_IRQ;
654 resource.IRQResource.IRQLevel = irq;
655 resource.IRQResource.PCIIrqPin = pin;
656 resource.IRQResource.IRQFlags = RS_IRQ_SHARED;
657
658 ret = RMAllocResource(rm_drvh, &ad_info->rm_irq, &resource);
659 if (ret != RMRC_SUCCESS) {
660 cprintf("%s: couldn't register IRQ %d (rc = %s)\n", drv_name, irq, rmerr(ret));
661 return;
662 }
663 rc_list->hResource[rc_list->NumResource++] = ad_info->rm_irq;
664
665 /* Allocate all I/O and MMIO addresses offered by this device. In theory,
666 * we need only BAR #5, the AHCI MMIO BAR, but in order to prevent any
667 * other driver from hijacking our device and accessing it via legacy
668 * registers we'll reserve anything we can find.
669 */
670
671 ddprintf("Adapter %d PCI=%d:%d:%d ID=%04x:%04x\n", ad_info_cnt, bus, dev_func>>3, dev_func&7, vendor, device);
672
673 for (i = 0; i < sizeof(ad_info->rm_bars) / sizeof(*ad_info->rm_bars); i++) {
674 long len = bar_resource(bus, dev_func, &resource, i);
675
676 if (len < 0) {
677 /* something went wrong */
678 goto add_pci_fail;
679 }
680 if (len == 0) {
681 /* this BAR is unused */
682 continue;
683 }
684
685 if (i == AHCI_PCI_BAR) {
686 if (resource.ResourceType != RS_TYPE_MEM) {
687 cprintf("%s: BAR #5 must be an MMIO region\n", drv_name);
688 goto add_pci_fail;
689 }
690 /* save this BAR's address as MMIO address */
691 ad_info->mmio_phys = resource.MEMResource.MemBase;
692 ad_info->mmio_size = resource.MEMResource.MemSize;
693 }
694
695 /* register [MM]IO region with resource manager */
696 ret = RMAllocResource(rm_drvh, ad_info->rm_bars + i, &resource);
697 if (ret != RMRC_SUCCESS) {
698 cprintf("%s: couldn't register [MM]IO region (rc = %s)\n",
699 drv_name, rmerr(ret));
700 goto add_pci_fail;
701 }
702 rc_list->hResource[rc_list->NumResource++] = ad_info->rm_bars[i];
703 }
704
705 if (ad_info->mmio_phys == 0) {
706 cprintf("%s: couldn't determine MMIO base address\n", drv_name);
707 goto add_pci_fail;
708 }
709
710 /****************************************************************************
711 * Part 3: Fill in the remaining fields in the AD_INFO slot and allocate
712 * memory and GDT selectors for the adapter. Finally, register the adapter
713 * itself with the OS/2 resource manager
714 */
715 ad_info->pci = pci_id;
716 ad_info->pci_vendor = vendor;
717 ad_info->pci_device = device;
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("%s: couldn't allocate DMA scratch buffers for AHCI ports\n", drv_name);
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("%s: couldn't allocate GDT selectors\n", drv_name);
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("%s: couldn't map MMIO address to GDT selector\n", drv_name);
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("%s: couldn't map DMA scratch buffer to GDT selector\n", drv_name);
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("%s: couldn't register adapter (rc = %s)\n", drv_name, 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 */
815UCHAR 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("%s: couldn't read config space (bus = %d, dev_func = 0x%02x, indx = 0x%02x, rc = %d)\n",
829 drv_name, 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 */
840UCHAR 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("%s: couldn't write config space (bus = %d, dev_func = 0x%02x, indx = 0x%02x, rc = %d)\n",
856 drv_name, 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("%s: couldn't attach to OEMHLP$\n", drv_name);
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("%s: couldn't determine [MM]IO size\n", drv_name);
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" : "MEM",
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.