source: trunk/src/os2ahci/pci.c

Last change on this file was 211, checked in by David Azarewicz, 2 years ago

Added workaround to help with VirtualBox issues.
Improved diagnostic messages.
Changed how timeouts are reset and how ctx hooks are triggered.
Added quirk for devices with issues executing some standard commands.
Changed to make /N the default.

File size: 29.9 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-2023 David Azarewicz <david@88watts.net>
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#include "pci_regs.h"
30
31/* offset of PCI base address register (BAR) in the PCI config space */
32#define PCI_BAR(reg) (UCHAR) (0x10 + (reg) * sizeof(u32))
33
34static void add_pci_device(PCI_ID *pci_id, USHORT BusDevFunc);
35static long bar_resource(USHORT BusDevFunc, RESOURCESTRUCT *resource, int i);
36static char *rmerr(APIRET ret);
37
38/******************************************************************************
39 * PCI vendor and device IDs for known AHCI adapters. Copied from the Linux
40 * AHCI driver.
41 */
42
43PCI_ID pci_ids[] =
44{
45 /* Intel
46 * NOTE: ICH5 controller does NOT support AHCI, so we do not add it here! */
47 { PCI_VDEVICE(INTEL, 0x2652), "ICH6" , 0 }, /* ICH6 */
48 { PCI_VDEVICE(INTEL, 0x2653), "ICH6M", 0 }, /* ICH6M */
49 { PCI_VDEVICE(INTEL, 0x27c1), "ICH7" , 0 }, /* ICH7 */
50 { PCI_VDEVICE(INTEL, 0x27c5), "ICH7M", 0 }, /* ICH7M */
51 { PCI_VDEVICE(INTEL, 0x27c3), "ICH7R", 0 }, /* ICH7R */
52 { PCI_VDEVICE(AL, 0x5288), "ULiM5288", AHCI_HFLAG_IGN_IRQ_IF_ERR }, /* ULi M5288 */
53 { PCI_VDEVICE(INTEL, 0x2681), "ESB2" , 0 }, /* ESB2 */
54 { PCI_VDEVICE(INTEL, 0x2682), "ESB2" , 0 }, /* ESB2 */
55 { PCI_VDEVICE(INTEL, 0x2683), "ESB2" , 0 }, /* ESB2 */
56 { PCI_VDEVICE(INTEL, 0x27c6), "ICH7MDH", 0 }, /* ICH7-M DH */
57 { PCI_VDEVICE(INTEL, 0x2821), "ICH8" , 0 }, /* ICH8 */
58 { PCI_VDEVICE(INTEL, 0x2822), "ICH8", AHCI_HFLAG_NO_SNTF }, /* ICH8 */
59 { PCI_VDEVICE(INTEL, 0x2824), "ICH8" , 0 }, /* ICH8 */
60 { PCI_VDEVICE(INTEL, 0x2829), "ICH8M" , 0 }, /* ICH8M */
61 { PCI_VDEVICE(INTEL, 0x282a), "ICH8M" , 0 }, /* ICH8M */
62 { PCI_VDEVICE(INTEL, 0x2922), "ICH9" , 0 }, /* ICH9 */
63 { PCI_VDEVICE(INTEL, 0x2923), "ICH9" , 0 }, /* ICH9 */
64 { PCI_VDEVICE(INTEL, 0x2924), "ICH9" , 0 }, /* ICH9 */
65 { PCI_VDEVICE(INTEL, 0x2925), "ICH9" , 0 }, /* ICH9 */
66 { PCI_VDEVICE(INTEL, 0x2927), "ICH9" , 0 }, /* ICH9 */
67 { PCI_VDEVICE(INTEL, 0x2929), "ICH9M" , 0 }, /* ICH9M */
68 { PCI_VDEVICE(INTEL, 0x292a), "ICH9M" , 0 }, /* ICH9M */
69 { PCI_VDEVICE(INTEL, 0x292b), "ICH9M" , 0 }, /* ICH9M */
70 { PCI_VDEVICE(INTEL, 0x292c), "ICH9M" , 0 }, /* ICH9M */
71 { PCI_VDEVICE(INTEL, 0x292f), "ICH9M" , 0 }, /* ICH9M */
72 { PCI_VDEVICE(INTEL, 0x294d), "ICH9" , 0 }, /* ICH9 */
73 { PCI_VDEVICE(INTEL, 0x294e), "ICH9M" , 0 }, /* ICH9M */
74 { PCI_VDEVICE(INTEL, 0x502a), "Tolapai" , 0 }, /* Tolapai */
75 { PCI_VDEVICE(INTEL, 0x502b), "Tolapai" , 0 }, /* Tolapai */
76 { PCI_VDEVICE(INTEL, 0x3a05), "ICH10" , 0 }, /* ICH10 */
77 { PCI_VDEVICE(INTEL, 0x3a22), "ICH10" , 0 }, /* ICH10 */
78 { PCI_VDEVICE(INTEL, 0x3a25), "ICH10" , 0 }, /* ICH10 */
79 { PCI_VDEVICE(INTEL, 0x3b22), "PCH AHCI", 0 }, /* PCH AHCI */
80 { PCI_VDEVICE(INTEL, 0x3b23), "PCH AHCI", 0 }, /* PCH AHCI */
81 { PCI_VDEVICE(INTEL, 0x3b24), "PCH RAID", 0 }, /* PCH RAID */
82 { PCI_VDEVICE(INTEL, 0x3b25), "PCH RAID", 0 }, /* PCH RAID */
83 { PCI_VDEVICE(INTEL, 0x3b29), "PCH AHCI", 0 }, /* PCH AHCI */
84 { PCI_VDEVICE(INTEL, 0x3b2b), "PCH RAID", 0 }, /* PCH RAID */
85 { PCI_VDEVICE(INTEL, 0x3b2c), "PCH RAID", 0 }, /* PCH RAID */
86 { PCI_VDEVICE(INTEL, 0x3b2f), "PCH AHCI", 0 }, /* PCH AHCI */
87
88 /* JMicron 360/1/3/5/6, match class to avoid IDE function */
89 { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
90 PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, "360", AHCI_HFLAG_IGN_IRQ_IF_ERR },
91
92 /* ATI */
93 { PCI_VDEVICE(ATI, 0x4380), "SB600", AHCI_HFLAG_IGN_SERR_INTERNAL | AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255 | AHCI_HFLAG_32BIT_ONLY }, /* ATI SB600 */
94 { PCI_VDEVICE(ATI, 0x4390), "SB700/800", AHCI_HFLAG_IGN_SERR_INTERNAL }, /* ATI SB700/800 */
95 { PCI_VDEVICE(ATI, 0x4391), "SB700/800", AHCI_HFLAG_IGN_SERR_INTERNAL }, /* ATI SB700/800 */
96 { PCI_VDEVICE(ATI, 0x4392), "SB700/800", AHCI_HFLAG_IGN_SERR_INTERNAL }, /* ATI SB700/800 */
97 { PCI_VDEVICE(ATI, 0x4393), "SB700/800", AHCI_HFLAG_IGN_SERR_INTERNAL }, /* ATI SB700/800 */
98 { PCI_VDEVICE(ATI, 0x4394), "SB700/800", AHCI_HFLAG_IGN_SERR_INTERNAL }, /* ATI SB700/800 */
99 { PCI_VDEVICE(ATI, 0x4395), "SB700/800", AHCI_HFLAG_IGN_SERR_INTERNAL }, /* ATI SB700/800 */
100
101 /* AMD */
102 { PCI_VDEVICE(AMD, 0x7800), "Hudson-2", 0 }, /* AMD Hudson-2 */
103 /* AMD is using RAID class only for ahci controllers */
104 { PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
105 PCI_CLASS_STORAGE_RAID << 8, 0xffffff, "Hudson2", 0 },
106
107 /* VIA */
108 { PCI_VDEVICE(VIA, 0x3349), "VT8251", AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP }, /* VIA VT8251 */
109 { PCI_VDEVICE(VIA, 0x6287), "VT8251", AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP }, /* VIA VT8251 */
110
111 /* NVIDIA */
112 { PCI_VDEVICE(NVIDIA, 0x044c), "MCP65", AHCI_HFLAG_YES_NCQ }, /* MCP65 */
113 { PCI_VDEVICE(NVIDIA, 0x044d), "MCB65", AHCI_HFLAG_YES_NCQ }, /* MCP65 */
114 { PCI_VDEVICE(NVIDIA, 0x044e), "MCP65", AHCI_HFLAG_YES_NCQ }, /* MCP65 */
115 { PCI_VDEVICE(NVIDIA, 0x044f), "MCP65", AHCI_HFLAG_YES_NCQ }, /* MCP65 */
116 { PCI_VDEVICE(NVIDIA, 0x045c), "MCP65", AHCI_HFLAG_YES_NCQ }, /* MCP65 */
117 { PCI_VDEVICE(NVIDIA, 0x045d), "MCP65", AHCI_HFLAG_YES_NCQ }, /* MCP65 */
118 { PCI_VDEVICE(NVIDIA, 0x045e), "MCP65", AHCI_HFLAG_YES_NCQ }, /* MCP65 */
119 { PCI_VDEVICE(NVIDIA, 0x045f), "MCP65", AHCI_HFLAG_YES_NCQ }, /* MCP65 */
120 { PCI_VDEVICE(NVIDIA, 0x0550), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
121 { PCI_VDEVICE(NVIDIA, 0x0551), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
122 { PCI_VDEVICE(NVIDIA, 0x0552), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
123 { PCI_VDEVICE(NVIDIA, 0x0553), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
124 { PCI_VDEVICE(NVIDIA, 0x0554), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
125 { PCI_VDEVICE(NVIDIA, 0x0555), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
126 { PCI_VDEVICE(NVIDIA, 0x0556), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
127 { PCI_VDEVICE(NVIDIA, 0x0557), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
128 { PCI_VDEVICE(NVIDIA, 0x0558), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
129 { PCI_VDEVICE(NVIDIA, 0x0559), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
130 { PCI_VDEVICE(NVIDIA, 0x055a), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
131 { PCI_VDEVICE(NVIDIA, 0x055b), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* MCP67 */
132 { PCI_VDEVICE(NVIDIA, 0x0580), "MCP67" , AHCI_HFLAG_YES_NCQ }, /* Linux ID */
133 { PCI_VDEVICE(NVIDIA, 0x07f0), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
134 { PCI_VDEVICE(NVIDIA, 0x07f1), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
135 { PCI_VDEVICE(NVIDIA, 0x07f2), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
136 { PCI_VDEVICE(NVIDIA, 0x07f3), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
137 { PCI_VDEVICE(NVIDIA, 0x07f4), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
138 { PCI_VDEVICE(NVIDIA, 0x07f5), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
139 { PCI_VDEVICE(NVIDIA, 0x07f6), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
140 { PCI_VDEVICE(NVIDIA, 0x07f7), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
141 { PCI_VDEVICE(NVIDIA, 0x07f8), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
142 { PCI_VDEVICE(NVIDIA, 0x07f9), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
143 { PCI_VDEVICE(NVIDIA, 0x07fa), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
144 { PCI_VDEVICE(NVIDIA, 0x07fb), "MCP73" , AHCI_HFLAG_YES_NCQ }, /* MCP73 */
145 { PCI_VDEVICE(NVIDIA, 0x0ad0), "MCP77", 0 }, /* MCP77 */
146 { PCI_VDEVICE(NVIDIA, 0x0ad1), "MCP77", 0 }, /* MCP77 */
147 { PCI_VDEVICE(NVIDIA, 0x0ad2), "MCP77", 0 }, /* MCP77 */
148 { PCI_VDEVICE(NVIDIA, 0x0ad3), "MCP77", 0 }, /* MCP77 */
149 { PCI_VDEVICE(NVIDIA, 0x0ad4), "MCP77", 0 }, /* MCP77 */
150 { PCI_VDEVICE(NVIDIA, 0x0ad5), "MCP77", 0 }, /* MCP77 */
151 { PCI_VDEVICE(NVIDIA, 0x0ad6), "MCP77", 0 }, /* MCP77 */
152 { PCI_VDEVICE(NVIDIA, 0x0ad7), "MCP77", 0 }, /* MCP77 */
153 { PCI_VDEVICE(NVIDIA, 0x0ad8), "MCP77", 0 }, /* MCP77 */
154 { PCI_VDEVICE(NVIDIA, 0x0ad9), "MCP77", 0 }, /* MCP77 */
155 { PCI_VDEVICE(NVIDIA, 0x0ada), "MCP77", 0 }, /* MCP77 */
156 { PCI_VDEVICE(NVIDIA, 0x0adb), "MCP77", 0 }, /* MCP77 */
157 { PCI_VDEVICE(NVIDIA, 0x0ab4), "MCP79", 0 }, /* MCP79 */
158 { PCI_VDEVICE(NVIDIA, 0x0ab5), "MCP79", 0 }, /* MCP79 */
159 { PCI_VDEVICE(NVIDIA, 0x0ab6), "MCP79", 0 }, /* MCP79 */
160 { PCI_VDEVICE(NVIDIA, 0x0ab7), "MCP79", 0 }, /* MCP79 */
161 { PCI_VDEVICE(NVIDIA, 0x0ab8), "MCP79", 0 }, /* MCP79 */
162 { PCI_VDEVICE(NVIDIA, 0x0ab9), "MCP79", 0 }, /* MCP79 */
163 { PCI_VDEVICE(NVIDIA, 0x0aba), "MCP79", 0 }, /* MCP79 */
164 { PCI_VDEVICE(NVIDIA, 0x0abb), "MCP79", 0 }, /* MCP79 */
165 { PCI_VDEVICE(NVIDIA, 0x0abc), "MCP79", 0 }, /* MCP79 */
166 { PCI_VDEVICE(NVIDIA, 0x0abd), "MCP79", 0 }, /* MCP79 */
167 { PCI_VDEVICE(NVIDIA, 0x0abe), "MCP79", 0 }, /* MCP79 */
168 { PCI_VDEVICE(NVIDIA, 0x0abf), "MCP79", 0 }, /* MCP79 */
169 { PCI_VDEVICE(NVIDIA, 0x0d84), "MCP89", 0 }, /* MCP89 */
170 { PCI_VDEVICE(NVIDIA, 0x0d85), "MCP89", 0 }, /* MCP89 */
171 { PCI_VDEVICE(NVIDIA, 0x0d86), "MCP89", 0 }, /* MCP89 */
172 { PCI_VDEVICE(NVIDIA, 0x0d87), "MCP89", 0 }, /* MCP89 */
173 { PCI_VDEVICE(NVIDIA, 0x0d88), "MCP89", 0 }, /* MCP89 */
174 { PCI_VDEVICE(NVIDIA, 0x0d89), "MCP89", 0 }, /* MCP89 */
175 { PCI_VDEVICE(NVIDIA, 0x0d8a), "MCP89", 0 }, /* MCP89 */
176 { PCI_VDEVICE(NVIDIA, 0x0d8b), "MCP89", 0 }, /* MCP89 */
177 { PCI_VDEVICE(NVIDIA, 0x0d8c), "MCP89", 0 }, /* MCP89 */
178 { PCI_VDEVICE(NVIDIA, 0x0d8d), "MCP89", 0 }, /* MCP89 */
179 { PCI_VDEVICE(NVIDIA, 0x0d8e), "MCP89", 0 }, /* MCP89 */
180 { PCI_VDEVICE(NVIDIA, 0x0d8f), "MCP89", 0 }, /* MCP89 */
181
182 /* SiS */
183 { PCI_VDEVICE(SI, 0x1184), "966", 0 }, /* SiS 966 */
184 { PCI_VDEVICE(SI, 0x1185), "968", 0 }, /* SiS 968 */
185 { PCI_VDEVICE(SI, 0x0186), "968", 0 }, /* SiS 968 */
186
187 /* Marvell */
188 { PCI_VDEVICE(MARVELL, 0x6145), "6145", AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI | AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP }, /* 6145 */
189 { PCI_VDEVICE(MARVELL, 0x6121), "6121", AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI | AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP }, /* 6121 */
190
191 /* Promise */
192 { PCI_VDEVICE(PROMISE, 0x3f20), "PDC42819", 0 }, /* PDC42819 */
193
194 /* Generic, PCI class code for AHCI */
195 { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
196 PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, "Generic", 0 },
197
198 /* end of list, including a few slots to define custom adapters (10) */
199 { 0, 0, 0, 0, 0, 0, NULL, 0 },
200 { 0, 0, 0, 0, 0, 0, NULL, 0 },
201 { 0, 0, 0, 0, 0, 0, NULL, 0 },
202 { 0, 0, 0, 0, 0, 0, NULL, 0 },
203 { 0, 0, 0, 0, 0, 0, NULL, 0 },
204 { 0, 0, 0, 0, 0, 0, NULL, 0 },
205 { 0, 0, 0, 0, 0, 0, NULL, 0 },
206 { 0, 0, 0, 0, 0, 0, NULL, 0 },
207 { 0, 0, 0, 0, 0, 0, NULL, 0 },
208 { 0, 0, 0, 0, 0, 0, NULL, 0 },
209
210 { 0, 0, 0, 0, 0, 0, NULL, 0 }
211};
212
213/******************************************************************************
214 * Add specified PCI vendor and device ID to the list of supported AHCI
215 * controllers. Please note that the last slot in pci_ids needs to remain
216 * empty because it's used as end marker.
217 */
218int add_pci_id(u16 vendor, u16 device)
219{
220 int max_slot = sizeof(pci_ids) / sizeof(*pci_ids) - 2;
221 int i;
222
223 /* search for last used slot in 'pci_ids' */
224 for (i = max_slot; i >= 0 && pci_ids[i].vendor == 0; i--);
225 if (i >= max_slot) return(-1); /* all slots in use */
226
227 /* use slot after the last used slot */
228 i++;
229 pci_ids[i].vendor = vendor;
230 pci_ids[i].device = device;
231 pci_ids[i].pChipName = "Specified";
232 pci_ids[i].quirks = 0;
233 return(0);
234}
235
236/******************************************************************************
237 * Scan PCI bus using OEMHLP$ IOCTLs and build adapter list.
238 */
239void scan_pci_bus(void)
240{
241 UCHAR index;
242 int ad_indx = 0;
243 int i;
244 int n;
245 USHORT BusDevFunc;
246
247 DPRINTF(DBG_INIT|DBG_FUNCBEG, DBG_PREFIX": scanning PCI bus...\n");
248
249 /* Go through the list of PCI IDs and search for each device
250 *
251 * NOTES:
252 *
253 * - When searching via class code, the OEMHLP$ interface doesn't allow
254 * setting a bitmask to look for individual portions of class code,
255 * subclass code and programming interface. However, all bitmasks in the
256 * PCI list currently use 0xffffff, thus this should not be a problem at
257 * this point in time.
258 *
259 * - Scanning via OEMHLP$ seems rather slow, at least in the virtual
260 * machine I'm currenly using to test this driver. Thus, class code
261 * scans are preferred unless the option "-t" (thorough_scan) has been
262 * specified. The assumption is that most, if not all, modern AHCI
263 * adapters have the correct class code (PCI_CLASS_STORAGE_SATA_AHCI).
264 */
265 for (i = 0; pci_ids[i].vendor != 0; i++)
266 {
267 index = 0;
268 do
269 {
270 if (pci_ids[i].device == PCI_ANY_ID || pci_ids[i].vendor == PCI_ANY_ID)
271 {
272 /* look for class code */
273 BusDevFunc = PciFindClass(pci_ids[i].class, index);
274 }
275 else if (thorough_scan)
276 {
277 /* look for this specific vendor and device ID */
278 BusDevFunc = PciFindDevice( pci_ids[i].vendor, pci_ids[i].device, index);
279
280 }
281 else
282 {
283 BusDevFunc = 0xffff;
284 }
285
286 if (BusDevFunc != 0xffff)
287 {
288 /* found a device */
289 int already_found = 0;
290
291 /* increment index for next loop */
292 if (++index > 180) return; /* something's wrong here... */
293
294 /* check whether we already found this device */
295 for (n = 0; n < ad_info_cnt; n++)
296 {
297 if (ad_infos[n].BusDevFunc == BusDevFunc)
298 {
299 /* this device has already been found (e.g. via thorough scan) */
300 already_found = 1;
301 break;
302 }
303 }
304
305 if (already_found || (ad_ignore & (1U << ad_indx++)))
306 {
307 /* ignore this device; it has either already been found via a
308 * thorough scan or has been specified to be ignored via command
309 * line option */
310 continue;
311 }
312
313 /* add this PCI device to ad_infos[] */
314 add_pci_device(pci_ids + i, BusDevFunc);
315 }
316
317 } while (BusDevFunc != 0xffff);
318 }
319}
320
321/******************************************************************************
322 * Hack to set up proper IRQ mappings in the emulated PIIX3 ISA bridge in
323 * VirtualBox (for some reason, the first mapped IRQ is 0x80 without this
324 * hack).
325 */
326void pci_hack_virtualbox(void)
327{
328 UCHAR irq = 0;
329
330 if (!PciReadConfig(0x0008, 0x60, sizeof(irq), &irq) && irq == 0x80)
331 {
332 /* set IRQ for first device/func to 11 */
333 DPRINTF(DBG_INIT, DBG_PREFIX": hacking virtualbox PIIX3 PCI to ISA bridge IRQ mapping\n");
334 irq = ad_infos[0].irq;
335 PciWriteConfig(0x0008, 0x60, sizeof(irq), irq);
336 }
337}
338
339/******************************************************************************
340 * Add a single PCI device to the list of adapters.
341 */
342static void add_pci_device(PCI_ID *pci_id, USHORT BusDevFunc)
343{
344 char rc_list_buf[sizeof(AHRESOURCE) + sizeof(HRESOURCE) * 15];
345 AHRESOURCE *rc_list = (AHRESOURCE *) rc_list_buf;
346 RESOURCESTRUCT resource;
347 ADAPTERSTRUCT adapter;
348 ADJUNCT adj;
349 AD_INFO *ad_info;
350 APIRET ret;
351 ULONG val;
352 char tmp[40];
353 u16 device;
354 u16 vendor;
355 u32 class;
356 int irq;
357 int pin;
358 int i;
359
360 /*****************************************************************************
361 * Part 1: Get further information about the device to be added; PCI ID...
362 */
363 if (PciReadConfig(BusDevFunc, 0x00, sizeof(ULONG), &val)) return;
364 device = (val >> 16);
365 vendor = (val & 0xffff);
366
367 /* ... and class code */
368 if (PciReadConfig(BusDevFunc, 0x08, sizeof(ULONG), &val)) return;
369 class = (val >> 8);
370
371 if (pci_id->device == PCI_ANY_ID)
372 {
373 /* We found this device in a wildcard search. There are two possible
374 * reasons which require a different handling:
375 *
376 * 1) This device uses a non-standard PCI class and has been identified
377 * with the corresponding class in pci_ids[] (e.g. the entry
378 * PCI_VENDOR_ID_JMICRON), but there is a vendor ID in pci_ids[]. In
379 * this case, we need to verify that the vendor is correct (see
380 * comments regarding OEMHLP limitations in 'scan_pci_bus()')
381 *
382 * 2) This device was identified using a generic PCI class for AHCI
383 * adapters such as PCI_CLASS_STORAGE_SATA_AHCI and we need to map
384 * the device and vendor ID to the corresponding index in pci_ids[]
385 * if there is such an entry; the index passed to this function will
386 * be the generic class-based index which is fine as long as there's
387 * not special treatment required as indicated by the board_*
388 * constants in pci_ids[]...
389 *
390 * The main reason for this kludge is that it seems as if OEMHLP$
391 * is rather slow searching for PCI devices, adding around 30s
392 * to the boot time when scanning for individual AHCI PCI IDs. Thus,
393 * the OS2AHCI driver avoids this kind of scan in favor of a class-
394 * based scan (unless overridden with the "/T" option).
395 */
396 if (pci_id->vendor != PCI_ANY_ID)
397 {
398 /* case 1: the vendor is known but we found the PCI device using a class
399 * search; verify vendor matches the one in pci_ids[]
400 */
401 if (pci_id->vendor != vendor) return; /* vendor doesn't match */
402 }
403 else
404 {
405 /* case 2: we found this device using a generic class search; if the
406 * device/vendor is listed in pci_ids[], use this entry in favor of the
407 * one passed in 'pci_id'
408 */
409 for (i = 0; pci_ids[i].vendor != 0; i++)
410 {
411 if (pci_ids[i].device == device && pci_ids[i].vendor == vendor)
412 {
413 pci_id = pci_ids + i;
414 break;
415 }
416 }
417 }
418 }
419
420 /* found a supported AHCI device */
421
422 if (PciReadConfig(BusDevFunc, 0x3c, sizeof(u32), &val)) return;
423 irq = (int) (val & 0xff);
424 pin = (int) ((val >> 8) & 0xff);
425
426 /* make sure we got room in the adapter information array */
427 if (ad_info_cnt >= MAX_AD - 1)
428 {
429 iprintf("OS2AHCI.ADD: too many AHCI devices");
430 return;
431 }
432
433 /****************************************************************************
434 * Part 2: Determine resource requirements and allocate resources with the
435 * OS/2 resource manager. While doing so, some of the entries of the
436 * corresponding slot in the AD_INFO array, namely resource manager
437 * handles, are initialized so we need prepare the slot.
438 *
439 * NOTE: While registering resources with the resource manager, each new
440 * resource is added to the corresponding rc_list.hResource[] slot.
441 * rc_list is used further down to associate resources to adapters
442 * when the adapter itself is registered with the OS/2 resource
443 * manager.
444 */
445 ad_info = ad_infos + ad_info_cnt;
446 memset(ad_info, 0x00, sizeof(*ad_info));
447 rc_list->NumResource = 0;
448
449 /* Allocate all I/O and MMIO addresses offered by this device. In theory,
450 * we need only BAR #5, the AHCI MMIO BAR, but in order to prevent any
451 * other driver from hijacking our device and accessing it via legacy
452 * registers we'll reserve anything we can find.
453 */
454
455 if (iVerbose)
456 {
457 iprintf("OS2AHCI.ADD: Adapter %d PCI=%d:%d:%d ID=%04x:%04x", ad_info_cnt, PCI_BUS_FROM_BDF(BusDevFunc),
458 PCI_DEV_FROM_BDF(BusDevFunc), PCI_FUNC_FROM_BDF(BusDevFunc), vendor, device);
459 }
460 DPRINTF(DBG_INIT, DBG_PREFIX": Adapter %d PCI=%d:%d:%d ID=%04x:%04x\n", ad_info_cnt, PCI_BUS_FROM_BDF(BusDevFunc),
461 PCI_DEV_FROM_BDF(BusDevFunc), PCI_FUNC_FROM_BDF(BusDevFunc), vendor, device);
462
463 for (i = 0; i < sizeof(ad_info->rm_bars) / sizeof(*ad_info->rm_bars); i++)
464 {
465 long len = bar_resource(BusDevFunc, &resource, i);
466
467 if (len < 0)
468 {
469 /* something went wrong */
470 goto add_pci_fail;
471 }
472 if (len == 0)
473 {
474 /* this BAR is unused */
475 continue;
476 }
477
478 if (i == AHCI_PCI_BAR)
479 {
480 if (resource.ResourceType != RS_TYPE_MEM)
481 {
482 iprintf("OS2AHCI.ADD: BAR #5 must be an MMIO region");
483 goto add_pci_fail;
484 }
485 /* save this BAR's address as MMIO address */
486 ad_info->mmio_phys = resource.MEMResource.MemBase;
487 ad_info->mmio_size = resource.MEMResource.MemSize;
488 }
489
490 /* register [MM]IO region with resource manager */
491 ret = RMAllocResource(rm_drvh, ad_info->rm_bars + i, &resource);
492 if (ret != RMRC_SUCCESS)
493 {
494 if (ret == RMRC_RES_ALREADY_CLAIMED)
495 {
496 if (iVerbose) iprintf("OS2AHCI.ADD: Device already claimed.");
497 }
498 else
499 {
500 iprintf("OS2AHCI.ADD: couldn't register [MM]IO region (rc = %s)", rmerr(ret));
501 }
502 goto add_pci_fail;
503 }
504 rc_list->hResource[rc_list->NumResource++] = ad_info->rm_bars[i];
505 }
506
507 if (ad_info->mmio_phys == 0)
508 {
509 iprintf("OS2AHCI.ADD: couldn't determine MMIO base address");
510 goto add_pci_fail;
511 }
512
513 /****************************************************************************
514 * Part 3: Fill in the remaining fields in the AD_INFO slot and allocate
515 * memory and GDT selectors for the adapter. Finally, register the adapter
516 * itself with the OS/2 resource manager
517 */
518 ad_info->pChipName = pci_id->pChipName;
519 ad_info->quirks = pci_id->quirks;
520 ad_info->PciVendor = vendor;
521 ad_info->PciDevice = device;
522 ad_info->BusDevFunc = BusDevFunc;
523 ad_info->irq = irq;
524 ad_info->irq_pin = pin;
525
526 ad_info->mmio = MapPhysToLin(ad_info->mmio_phys, ad_info->mmio_size);
527 if (!ad_info->mmio) goto add_pci_fail;
528
529 /* register adapter with resource manager */
530 memset(&adj, 0x00, sizeof(adj));
531 adj.pNextAdj = NULL;
532 adj.AdjLength = sizeof(adj);
533 adj.AdjType = ADJ_ADAPTER_NUMBER;
534 adj.Adapter_Number = ad_info_cnt;
535
536 memset(&adapter, 0x00, sizeof(adapter));
537 snprintf(tmp, sizeof(tmp), "AHCI_%d Controller", ad_info_cnt);
538 adapter.AdaptDescriptName = tmp;
539 adapter.AdaptFlags = 0;
540 adapter.BaseType = AS_BASE_MSD;
541 adapter.SubType = AS_SUB_IDE;
542 adapter.InterfaceType = AS_INTF_GENERIC;
543 adapter.HostBusType = AS_HOSTBUS_PCI;
544 adapter.HostBusWidth = AS_BUSWIDTH_32BIT;
545 adapter.pAdjunctList = &adj;
546
547 ret = RMCreateAdapter(rm_drvh, &ad_info->rm_adh, &adapter, NULL, rc_list);
548 if (ret != RMRC_SUCCESS)
549 {
550 iprintf("OS2AHCI.ADD: couldn't register adapter (rc = %s)", rmerr(ret));
551 goto add_pci_fail;
552 }
553
554 if (!PciReadConfig(BusDevFunc, PCI_COMMAND, 2, &val))
555 {
556 val |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
557 val &= ~PCI_COMMAND_INTX_DISABLE;
558 PciWriteConfig(BusDevFunc, PCI_COMMAND, 2, val);
559 }
560 if (ahci_config_caps(ad_info)) goto add_pci_fail;
561
562 #ifndef DAZ_NEW_CODE
563 /* fill in DMA scratch buffer addresses in adapter info */
564 for (i = 0; i < AHCI_MAX_PORTS; i++)
565 {
566 if (!(ad_info->port_map & (1UL << i))) continue;
567
568 ad_info->ports[i].dma_buf = MemAllocAlign(AHCI_PORT_PRIV_DMA_SZ, 1024);
569 ad_info->ports[i].dma_buf_phys = MemPhysAdr(ad_info->ports[i].dma_buf);
570 }
571 #endif
572
573 /* Successfully added the adapter and reserved its resources; the adapter
574 * is still under BIOS control so we're not going to do anything else at
575 * this point.
576 */
577
578 ad_info_cnt++;
579 return;
580
581add_pci_fail:
582 /* something went wrong; try to clean up as far as possible */
583 for (i = 0; i < sizeof(ad_info->rm_bars) / sizeof(*ad_info->rm_bars); i++)
584 {
585 if (ad_info->rm_bars[i] != 0) RMDeallocResource(rm_drvh, ad_info->rm_bars[i]);
586 }
587}
588
589/******************************************************************************
590 * Prepare a resource structure for a PCI Base Address Register (BAR). This
591 * basically means the type, address and range of the I/O address space. It
592 * returns the length of the address range as a signed long to allow the caller
593 * to differentiate between error conditions (< 0), unused BARs (0) or valid
594 * bars (> 0).
595 *
596 * NOTE: In order to do this, we need to temporarily write 0xffffffff to
597 * the MMIO base address register (BAR), read back the resulting value
598 * and check the 0 bits from the right end, masking the lower 2 (I/O) or
599 * 4 (MMIO) bits. After doing this, we must restore the original value
600 * set up by the BIOS.
601 *
602 * 31 4 3 2 1 0
603 * -------------------------------------------------------------------
604 * base address P T T I
605 * P = prefetchable
606 * T = type (0 = any 32 bit, 1 = <1M, 2 = 64 bit)
607 * I = I/O (1) or memory (0)
608 */
609static long bar_resource(USHORT BusDevFunc, RESOURCESTRUCT *resource, int i)
610{
611 u32 bar_addr = 0;
612 u32 bar_size = 0;
613
614 /* temporarily write 1s to this BAR to determine the address range */
615 if (PciReadConfig (BusDevFunc, PCI_BAR(i), sizeof(u32), &bar_addr) ||
616 PciWriteConfig(BusDevFunc, PCI_BAR(i), sizeof(u32), ~(0UL)) ||
617 PciReadConfig (BusDevFunc, PCI_BAR(i), sizeof(u32), &bar_size) ||
618 PciWriteConfig(BusDevFunc, PCI_BAR(i), sizeof(u32), bar_addr) )
619 {
620 iprintf("OS2AHCI.ADD: couldn't determine [MM]IO size");
621 if (bar_addr != 0)
622 {
623 PciWriteConfig(BusDevFunc, PCI_BAR(i), sizeof(u32), bar_addr);
624 }
625 return(-1);
626 }
627
628 /* bar not implemented or device not working properly */
629 if (bar_size == 0 || bar_size == 0xffffffffUL) return(0);
630
631 /* prepare resource allocation structure */
632 memset(resource, 0x00, sizeof(*resource));
633 if (bar_addr & 1)
634 {
635 bar_size = ~(bar_size & 0xfffffffcUL) + 1;
636 bar_size &= 0xffffUL; /* I/O address space is 16 bits on x86 */
637 bar_addr &= 0xfffcUL;
638
639 resource->ResourceType = RS_TYPE_IO;
640 resource->IOResource.BaseIOPort = bar_addr;
641 resource->IOResource.NumIOPorts = bar_size;
642 resource->IOResource.IOFlags = RS_IO_EXCLUSIVE;
643 resource->IOResource.IOAddressLines = 16;
644
645 }
646 else
647 {
648 bar_size = ~(bar_size & 0xfffffff0UL) + 1;
649 bar_addr &= 0xfffffff0UL;
650
651 resource->ResourceType = RS_TYPE_MEM;
652 resource->MEMResource.MemBase = bar_addr;
653 resource->MEMResource.MemSize = bar_size;
654 resource->MEMResource.MemFlags = RS_MEM_EXCLUSIVE;
655 }
656
657 DPRINTF(DBG_INIT, DBG_PREFIX": BAR #%d: type = %s, addr = 0x%08lx, size = %d\n", i,
658 (resource->ResourceType == RS_TYPE_IO) ? "I/O" : "MEM", bar_addr, bar_size);
659
660 return((long) bar_size);
661}
662
663/******************************************************************************
664 * return vendor name for PCI vendor ID
665 */
666char *vendor_from_id(u16 id)
667{
668
669 switch(id)
670 {
671 case PCI_VENDOR_ID_AL:
672 return "Ali";
673 case PCI_VENDOR_ID_AMD:
674 case PCI_VENDOR_ID_ATI:
675 return "AMD";
676 case PCI_VENDOR_ID_AT:
677 return "Allied Telesyn";
678 case PCI_VENDOR_ID_ATT:
679 return "ATT";
680 case PCI_VENDOR_ID_CMD:
681 return "CMD";
682 case PCI_VENDOR_ID_CT:
683 return "CT";
684 case PCI_VENDOR_ID_INTEL:
685 return "Intel";
686 case PCI_VENDOR_ID_INITIO:
687 return "Initio";
688 case PCI_VENDOR_ID_JMICRON:
689 return "JMicron";
690 case PCI_VENDOR_ID_MARVELL:
691 return "Marvell";
692 case PCI_VENDOR_ID_NVIDIA:
693 return "NVIDIA";
694 case PCI_VENDOR_ID_PROMISE:
695 return "PROMISE";
696 case PCI_VENDOR_ID_SI:
697 return "SiS";
698 case PCI_VENDOR_ID_VIA:
699 return "VIA";
700 default:
701 break;
702 }
703
704 return "";
705}
706
707/******************************************************************************
708 * Return textual version of a resource manager error
709 */
710static char *rmerr(APIRET ret)
711{
712 switch (ret) {
713 case RMRC_SUCCESS:
714 return("RMRC_SUCCESS");
715 case RMRC_NOTINITIALIZED:
716 return("RMRC_NOTINITIALIZED");
717 case RMRC_BAD_DRIVERHANDLE:
718 return("RMRC_BAD_DRIVERHANDLE");
719 case RMRC_BAD_ADAPTERHANDLE:
720 return("RMRC_BAD_ADAPTERHANDLE");
721 case RMRC_BAD_DEVICEHANDLE:
722 return("RMRC_BAD_DEVICEHANDLE");
723 case RMRC_BAD_RESOURCEHANDLE:
724 return("RMRC_BAD_RESOURCEHANDLE");
725 case RMRC_BAD_LDEVHANDLE:
726 return("RMRC_BAD_LDEVHANDLE");
727 case RMRC_BAD_SYSNAMEHANDLE:
728 return("RMRC_BAD_SYSNAMEHANDLE");
729 case RMRC_BAD_DEVHELP:
730 return("RMRC_BAD_DEVHELP");
731 case RMRC_NULL_POINTER:
732 return("RMRC_NULL_POINTER");
733 case RMRC_NULL_STRINGS:
734 return("RMRC_NULL_STRINGS");
735 case RMRC_BAD_VERSION:
736 return("RMRC_BAD_VERSION");
737 case RMRC_RES_ALREADY_CLAIMED:
738 return("RMRC_RES_ALREADY_CLAIMED");
739 case RMRC_DEV_ALREADY_CLAIMED:
740 return("RMRC_DEV_ALREADY_CLAIMED");
741 case RMRC_INVALID_PARM_VALUE:
742 return("RMRC_INVALID_PARM_VALUE");
743 case RMRC_OUT_OF_MEMORY:
744 return("RMRC_OUT_OF_MEMORY");
745 case RMRC_SEARCH_FAILED:
746 return("RMRC_SEARCH_FAILED");
747 case RMRC_BUFFER_TOO_SMALL:
748 return("RMRC_BUFFER_TOO_SMALL");
749 case RMRC_GENERAL_FAILURE:
750 return("RMRC_GENERAL_FAILURE");
751 case RMRC_IRQ_ENTRY_ILLEGAL:
752 return("RMRC_IRQ_ENTRY_ILLEGAL");
753 case RMRC_NOT_IMPLEMENTED:
754 return("RMRC_NOT_IMPLEMENTED");
755 case RMRC_NOT_INSTALLED:
756 return("RMRC_NOT_INSTALLED");
757 case RMRC_BAD_DETECTHANDLE:
758 return("RMRC_BAD_DETECTHANDLE");
759 case RMRC_BAD_RMHANDLE:
760 return("RMRC_BAD_RMHANDLE");
761 case RMRC_BAD_FLAGS:
762 return("RMRC_BAD_FLAGS");
763 case RMRC_NO_DETECTED_DATA:
764 return("RMRC_NO_DETECTED_DATA");
765 default:
766 return("RMRC_UNKOWN");
767 }
768}
Note: See TracBrowser for help on using the repository browser.