VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/BIOS/ahci.c@ 37176

Last change on this file since 37176 was 36877, checked in by vboxsync, 14 years ago

BIOS: AHCI driver skeleton

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.8 KB
Line 
1/* $Id: ahci.c 36877 2011-04-28 19:38:13Z vboxsync $ */
2/** @file
3 * AHCI host adapter driver to boot from SATA disks.
4 */
5
6/*
7 * Copyright (C) 2011 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/** Supported methods of the PCI BIOS. */
19#define PCIBIOS_ID 0xb1
20#define PCIBIOS_PCI_BIOS_PRESENT 0x01
21#define PCIBIOS_FIND_PCI_DEVICE 0x02
22#define PCIBIOS_FIND_CLASS_CODE 0x03
23#define PCIBIOS_GENERATE_SPECIAL_CYCLE 0x06
24#define PCIBIOS_READ_CONFIG_BYTE 0x08
25#define PCIBIOS_READ_CONFIG_WORD 0x09
26#define PCIBIOS_READ_CONFIG_DWORD 0x0a
27#define PCIBIOS_WRITE_CONFIG_BYTE 0x0b
28#define PCIBIOS_WRITE_CONFIG_WORD 0x0c
29#define PCIBIOS_WRITE_CONFIG_DWORD 0x0d
30#define PCIBIOS_GET_IRQ_ROUTING_OPTIONS 0x0e
31#define PCIBIOS_SET_PCI_IRQ 0x0f
32
33/** Status codes. */
34#define SUCCESSFUL 0x00
35#define FUNC_NOT_SUPPORTED 0x81
36#define BAD_VENDOR_ID 0x83
37#define DEVICE_NOT_FOUND 0x86
38#define BAD_REGISTER_NUMBER 0x87
39#define SET_FAILED 0x88
40#define BUFFER_TOO_SMALL 0x89
41
42/** PCI configuration fields. */
43#define PCI_CONFIG_CAP 0x34
44
45#define PCI_CAP_ID_SATACR 0x12
46#define VBOX_AHCI_NO_DEVICE 0xffff
47
48#define VBOX_AHCI_DEBUG 1 /* temporary */
49
50#ifdef VBOX_AHCI_DEBUG
51# define VBOXAHCI_DEBUG(a...) BX_INFO(a)
52#else
53# define VBOXAHCI_DEBUG(a...)
54#endif
55
56#define RT_BIT_32(bit) ((Bit32u)(1 << (bit)))
57
58/** Global register set. */
59#define AHCI_HBA_SIZE 0x100
60
61#define AHCI_REG_CAP ((Bit32u)0x00)
62#define AHCI_REG_GHC ((Bit32u)0x04)
63# define AHCI_GHC_AE RT_BIT_32(31)
64# define AHCI_GHC_IR RT_BIT_32(1)
65# define AHCI_GHC_HR RT_BIT_32(0)
66#define AHCI_REG_IS ((Bit32u)0x08)
67#define AHCI_REG_PI ((Bit32u)0x0c)
68#define AHCI_REG_VS ((Bit32u)0x10)
69
70/** Per port register set. */
71#define AHCI_PORT_SIZE 0x80
72
73#define AHCI_REG_PORT_CLB 0x00
74#define AHCI_REG_PORT_CLBU 0x04
75#define AHCI_REG_PORT_FB 0x08
76#define AHCI_REG_PORT_FBU 0x0c
77#define AHCI_REG_PORT_IS 0x10
78#define AHCI_REG_PORT_IE 0x14
79#define AHCI_REG_PORT_CMD 0x18
80# define AHCI_REG_PORT_CMD_ST RT_BIT_32(0)
81# define AHCI_REG_PORT_CMD_FRE RT_BIT_32(4)
82# define AHCI_REG_PORT_CMD_FR RT_BIT_32(14)
83# define AHCI_REG_PORT_CMD_CR RT_BIT_32(15)
84#define AHCI_REG_PORT_TFD 0x20
85#define AHCI_REG_PORT_SIG 0x24
86#define AHCI_REG_PORT_SSTS 0x28
87#define AHCI_REG_PORT_SCTL 0x2c
88#define AHCI_REG_PORT_SERR 0x30
89#define AHCI_REG_PORT_SACT 0x34
90#define AHCI_REG_PORT_CI 0x38
91
92/** Returns the absolute register offset from a given port and port register. */
93#define VBOXAHCI_PORT_REG(port, reg) ((Bit32u)(AHCI_HBA_SIZE + (port) * AHCI_PORT_SIZE + (reg)))
94
95#define VBOXAHCI_REG_IDX 0
96#define VBOXAHCI_REG_DATA 4
97
98/** Writes the given value to a AHCI register. */
99#define VBOXAHCI_WRITE_REG(iobase, reg, val) \
100 outl((iobase) + VBOXAHCI_REG_IDX, (Bit32u)(reg)); \
101 outl((iobase) + VBOXAHCI_REG_DATA, (Bit32u)(val))
102
103/** Reads from a AHCI register. */
104#define VBOXAHCI_READ_REG(iobase, reg, val) \
105 outl((iobase) + VBOXAHCI_REG_IDX, (Bit32u)(reg)); \
106 (val) = inl((iobase) + VBOXAHCI_REG_DATA)
107
108/** Writes to the given port register. */
109#define VBOXAHCI_PORT_WRITE_REG(iobase, port, reg, val) \
110 VBOX_AHCI_WRITE_REG((iobase), VBOXAHCI_PORT_REG((port), (reg)), val)
111
112/** Reads from the given port register. */
113#define VBOXAHCI_PORT_READ_REG(iobase, port, reg, val) \
114 VBOX_AHCI_READ_REG((iobase), VBOXAHCI_PORT_REG((port), (reg)), val)
115
116/**
117 * Returns the bus/device/function of a PCI device with
118 * the given classcode.
119 *
120 * @returns bus/device/fn in one 16bit integer where
121 * where the upper byte contains the bus number
122 * and lower one the device and function number.
123 * VBOX_AHCI_NO_DEVICE if no device was found.
124 * @param u16Class The classcode to search for.
125 */
126Bit16u ahci_pci_find_classcode(u16Class)
127 Bit32u u16Class;
128{
129 Bit16u u16BusDevFn;
130
131ASM_START
132 push bp
133 mov bp, sp
134
135 mov ah, #PCIBIOS_ID
136 mov al, #PCIBIOS_FIND_CLASS_CODE
137 mov ecx, _ahci_pci_find_classcode.u16Class + 2[bp]
138 mov si, #0 ; First controller
139 int 0x1a
140
141 ; Return from PCIBIOS
142 cmp ah, #SUCCESSFUL
143 jne ahci_pci_find_classcode_not_found
144
145 mov _ahci_pci_find_classcode.u16BusDevFn + 2[bp], bx
146 jmp ahci_pci_find_classcode_done
147
148ahci_pci_find_classcode_not_found:
149 mov _ahci_pci_find_classcode.u16BusDevFn + 2[bp], #VBOX_AHCI_NO_DEVICE
150
151ahci_pci_find_classcode_done:
152 pop bp
153ASM_END
154
155 return u16BusDevFn;
156}
157
158Bit8u ahci_pci_read_config_byte(u8Bus, u8DevFn, u8Reg)
159 Bit8u u8Bus, u8DevFn, u8Reg;
160{
161 uint8_t u8Val;
162
163 u8Val = 0;
164
165ASM_START
166 push bp
167 mov bp, sp
168
169 mov ah, #PCIBIOS_ID
170 mov al, #PCIBIOS_READ_CONFIG_BYTE
171 mov bh, _ahci_pci_read_config_byte.u8Bus + 2[bp]
172 mov bl, _ahci_pci_read_config_byte.u8DevFn + 2[bp]
173 mov di, _ahci_pci_read_config_byte.u8Reg + 2[bp]
174 int 0x1a
175
176 ; Return from PCIBIOS
177 cmp ah, #SUCCESSFUL
178 jne ahci_pci_read_config_byte_done
179
180 mov _ahci_pci_read_config_byte.u8Val + 2[bp], cl
181
182ahci_pci_read_config_byte_done:
183 pop bp
184ASM_END
185
186 return u8Val;
187}
188
189Bit16u ahci_pci_read_config_word(u8Bus, u8DevFn, u8Reg)
190 Bit8u u8Bus, u8DevFn, u8Reg;
191{
192 Bit16u u16Val;
193
194 u16Val = 0;
195
196ASM_START
197 push bp
198 mov bp, sp
199
200 mov ah, #PCIBIOS_ID
201 mov al, #PCIBIOS_READ_CONFIG_WORD
202 mov bh, _ahci_pci_read_config_word.u8Bus + 2[bp]
203 mov bl, _ahci_pci_read_config_word.u8DevFn + 2[bp]
204 mov di, _ahci_pci_read_config_word.u8Reg + 2[bp]
205 int 0x1a
206
207 ; Return from PCIBIOS
208 cmp ah, #SUCCESSFUL
209 jne ahci_pci_read_config_word_done
210
211 mov _ahci_pci_read_config_word.u16Val + 2[bp], cx
212
213ahci_pci_read_config_word_done:
214 pop bp
215ASM_END
216
217 return u16Val;
218}
219
220Bit32u ahci_pci_read_config_dword(u8Bus, u8DevFn, u8Reg)
221 Bit8u u8Bus, u8DevFn, u8Reg;
222{
223 Bit32u u32Val;
224
225 u32Val = 0;
226
227ASM_START
228 push bp
229 mov bp, sp
230
231 mov ah, #PCIBIOS_ID
232 mov al, #PCIBIOS_READ_CONFIG_DWORD
233 mov bh, _ahci_pci_read_config_dword.u8Bus + 2[bp]
234 mov bl, _ahci_pci_read_config_dword.u8DevFn + 2[bp]
235 mov di, _ahci_pci_read_config_dword.u8Reg + 2[bp]
236 int 0x1a
237
238 ; Return from PCIBIOS
239 cmp ah, #SUCCESSFUL
240 jne ahci_pci_read_config_dword_done
241
242 mov _ahci_pci_read_config_dword.u32Val + 2[bp], ecx
243
244ahci_pci_read_config_dword_done:
245 pop bp
246ASM_END
247
248 return u32Val;
249}
250
251#if 0 /* Disabled to save space because they are not needed. Might become useful in the future. */
252/**
253 * Returns the bus/device/function of a PCI device with
254 * the given vendor and device id.
255 *
256 * @returns bus/device/fn in one 16bit integer where
257 * where the upper byte contains the bus number
258 * and lower one the device and function number.
259 * VBOX_AHCI_NO_DEVICE if no device was found.
260 * @param u16Vendor The vendor ID.
261 * @param u16Device The device ID.
262 */
263Bit16u ahci_pci_find_device(u16Vendor, u16Device)
264 Bit16u u16Vendor;
265 Bit16u u16Device;
266{
267 Bit16u u16BusDevFn;
268
269ASM_START
270 push bp
271 mov bp, sp
272
273 mov ah, #PCIBIOS_ID
274 mov al, #PCIBIOS_FIND_PCI_DEVICE
275 mov cx, _ahci_pci_find_device.u16Device + 2[bp]
276 mov dx, _ahci_pci_find_device.u16Vendor + 2[bp]
277 mov si, #0 ; First controller
278 int 0x1a
279
280 ; Return from PCIBIOS
281 cmp ah, #SUCCESSFUL
282 jne ahci_pci_find_device_not_found
283
284 mov _ahci_pci_find_device.u16BusDevFn + 2[bp], bx
285 jmp ahci_pci_find_device_done
286
287ahci_pci_find_device_not_found:
288 mov _ahci_pci_find_device.u16BusDevFn + 2[bp], #VBOX_AHCI_NO_DEVICE
289
290ahci_pci_find_device_done:
291 pop bp
292ASM_END
293
294 return u16BusDevFn;
295}
296
297void ahci_pci_write_config_byte(u8Bus, u8DevFn, u8Reg, u8Val)
298 Bit8u u8Bus, u8DevFn, u8Reg, u8Val;
299{
300ASM_START
301 push bp
302 mov bp, sp
303
304 mov ah, #PCIBIOS_ID
305 mov al, #PCIBIOS_WRITE_CONFIG_BYTE
306 mov bh, _ahci_pci_write_config_byte.u8Bus + 2[bp]
307 mov bl, _ahci_pci_write_config_byte.u8DevFn + 2[bp]
308 mov di, _ahci_pci_write_config_byte.u8Reg + 2[bp]
309 mov cl, _ahci_pci_write_config_byte.u8Val + 2[bp]
310 int 0x1a
311
312 ; Return from PCIBIOS
313 pop bp
314ASM_END
315}
316
317void ahci_pci_write_config_word(u8Bus, u8DevFn, u8Reg, u16Val)
318 Bit8u u8Bus, u8DevFn, u8Reg;
319 Bit16u u16Val;
320{
321ASM_START
322 push bp
323 mov bp, sp
324
325 mov ah, #PCIBIOS_ID
326 mov al, #PCIBIOS_WRITE_CONFIG_WORD
327 mov bh, _ahci_pci_write_config_word.u8Bus + 2[bp]
328 mov bl, _ahci_pci_write_config_word.u8DevFn + 2[bp]
329 mov di, _ahci_pci_write_config_word.u8Reg + 2[bp]
330 mov cx, _ahci_pci_write_config_word.u16Val + 2[bp]
331 int 0x1a
332
333 ; Return from PCIBIOS
334 pop bp
335ASM_END
336}
337
338void ahci_pci_write_config_dword(u8Bus, u8DevFn, u8Reg, u32Val)
339 Bit8u u8Bus, u8DevFn, u8Reg;
340 Bit32u u32Val;
341{
342ASM_START
343 push bp
344 mov bp, sp
345
346 mov ah, #PCIBIOS_ID
347 mov al, #PCIBIOS_WRITE_CONFIG_WORD
348 mov bh, _ahci_pci_write_config_dword.u8Bus + 2[bp]
349 mov bl, _ahci_pci_write_config_dword.u8DevFn + 2[bp]
350 mov di, _ahci_pci_write_config_dword.u8Reg + 2[bp]
351 mov cx, _ahci_pci_write_config_dword.u32Val + 2[bp]
352 int 0x1a
353
354 ; Return from PCIBIOS
355 pop bp
356ASM_END
357}
358#endif /* 0 */
359
360/**
361 * Sets a given set of bits in a register.
362 */
363static void ahci_ctrl_set_bits(u16IoBase, u32Reg, u32Set)
364 Bit16u u16IoBase;
365 Bit32u u32Reg, u32Set;
366{
367ASM_START
368 push bp
369 mov bp, sp
370
371 push eax
372 push edx
373
374 ; Read from the register
375 mov eax, _ahci_ctrl_set_bits.u32Reg + 2[bp]
376 mov dx, _ahci_ctrl_set_bits.u16IoBase + 2[bp]
377 add dx, #VBOXAHCI_REG_IDX
378 out dx, eax
379
380 mov dx, _ahci_ctrl_set_bits.u16IoBase + 2[bp]
381 add dx, #VBOXAHCI_REG_DATA
382 in eax, dx
383
384 ; Set the new bits and write the result to the register again
385 or eax, _ahci_ctrl_set_bits.u32Set + 2[bp]
386 out dx, eax
387
388 pop edx
389 pop eax
390
391 pop bp
392ASM_END
393}
394
395/**
396 * Clears a given set of bits in a register.
397 */
398static void ahci_ctrl_clear_bits(u16IoBase, u32Reg, u32Clear)
399 Bit16u u16IoBase;
400 Bit32u u32Reg, u32Clear;
401{
402ASM_START
403 push bp
404 mov bp, sp
405
406 push eax
407 push ecx
408 push edx
409
410 ; Read from the register
411 mov eax, _ahci_ctrl_clear_bits.u32Reg + 2[bp]
412 mov dx, _ahci_ctrl_clear_bits.u16IoBase + 2[bp]
413 add dx, #VBOXAHCI_REG_IDX
414 out dx, eax
415
416 mov dx, _ahci_ctrl_clear_bits.u16IoBase + 2[bp]
417 add dx, #VBOXAHCI_REG_DATA
418 in eax, dx
419
420 ; Clear the bits and write the result to the register again
421 mov ecx, _ahci_ctrl_clear_bits.u32Clear + 2[bp]
422 not ecx
423 and eax, ecx
424 out dx, eax
425
426 pop edx
427 pop ecx
428 pop eax
429
430 pop bp
431ASM_END
432}
433
434/**
435 * Returns whether at least one of the bits in the given mask is set
436 * for a register.
437 */
438static Bit8u ahci_ctrl_is_bit_set(u16IoBase, u32Reg, u32Mask)
439 Bit16u u16IoBase;
440 Bit32u u32Reg, u32Mask;
441{
442ASM_START
443 push bp
444 mov bp, sp
445
446 push eax
447 push edx
448
449 ; Read from the register
450 mov eax, _ahci_ctrl_is_bit_set.u32Reg + 2[bp]
451 mov dx, _ahci_ctrl_is_bit_set.u16IoBase + 2[bp]
452 add dx, #VBOXAHCI_REG_IDX
453 out dx, eax
454
455 mov dx, _ahci_ctrl_is_bit_set.u16IoBase + 2[bp]
456 add dx, #VBOXAHCI_REG_DATA
457 in eax, dx
458
459 ; Check for set bits
460 test eax, _ahci_ctrl_is_bit_set.u32Mask + 2[bp]
461 je ahci_ctrl_is_bit_set_not_set
462 mov al, #1 ; At least one of the bits is set
463 jmp ahci_ctrl_is_bit_set_done
464
465ahci_ctrl_is_bit_set_not_set:
466 mov al, #0 ; No bit is set
467
468ahci_ctrl_is_bit_set_done:
469 pop edx
470 pop eax
471
472 pop bp
473ASM_END
474}
475
476/**
477 * Extracts a range of bits from a register and shifts them
478 * to the right.
479 */
480static Bit16u ahci_ctrl_extract_bits(u32Reg, u32Mask, u8Shift)
481 Bit32u u32Reg, u32Mask, u8Shift;
482{
483ASM_START
484 push bp
485 mov bp, sp
486
487 push cx
488
489 mov eax, _ahci_ctrl_extract_bits.u32Reg + 2[bp]
490 mov cl, _ahci_ctrl_extract_bits.u8Shift + 2[bp]
491 and eax, _ahci_ctrl_extract_bits.u32Mask + 2[bp]
492 shr eax, cl
493
494 pop cx
495
496 pop bp
497ASM_END
498}
499
500static int ahci_port_init(u16IoBase, u8Port)
501 Bit16u u16IoBase;
502 Bit8u u8Port;
503{
504
505 /* Put the port into an idle state. */
506 ahci_ctrl_clear_bits(u16IoBase, VBOXAHCI_PORT_REG(u8Port, AHCI_REG_PORT_CMD),
507 AHCI_REG_PORT_CMD_FRE | AHCI_REG_PORT_CMD_ST);
508
509 while (ahci_ctrl_is_bit_set(u16IoBase, VBOXAHCI_PORT_REG(u8Port, AHCI_REG_PORT_CMD),
510 AHCI_REG_PORT_CMD_FRE | AHCI_REG_PORT_CMD_ST | AHCI_REG_PORT_CMD_FRE | AHCI_REG_PORT_CMD_CR) == 1)
511 {
512 VBOXAHCI_DEBUG("AHCI: Waiting for the port to idle\n");
513 }
514
515 /*
516 * Port idles, set up memory for commands and received FIS and program the
517 * address registers.
518 */
519
520 return -1;
521}
522
523static int ahci_ctrl_init(u16IoBase)
524 Bit16u u16IoBase;
525{
526 int rc = 0;
527 Bit8u i, cPorts;
528 Bit32u val;
529
530 VBOXAHCI_READ_REG(u16IoBase, AHCI_REG_VS, val);
531 VBOXAHCI_DEBUG("AHCI: Controller has version: 0x%x (major) 0x%x (minor)\n",
532 ahci_ctrl_extract_bits(val, 0xffff0000, 16),
533 ahci_ctrl_extract_bits(val, 0x0000ffff, 0));
534
535 /* Reset the controller. */
536 ahci_ctrl_set_bits(u16IoBase, AHCI_REG_GHC, AHCI_GHC_HR);
537 do
538 {
539 VBOXAHCI_READ_REG(u16IoBase, AHCI_REG_GHC, val);
540 } while (val & AHCI_GHC_HR != 0);
541
542 VBOXAHCI_READ_REG(u16IoBase, AHCI_REG_CAP, val);
543 cPorts = ahci_ctrl_extract_bits(val, 0x1f, 0) + 1; /* Extract number of ports.*/
544
545 VBOXAHCI_DEBUG("AHCI: Controller has %u ports\n", cPorts);
546
547 /* Go through the ports. */
548 i = 0;
549 while (i < 32)
550 {
551 if (ahci_ctrl_is_bit_set(u16IoBase, AHCI_REG_PI, RT_BIT_32(i)) != 0)
552 {
553 VBOXAHCI_DEBUG("AHCI: Port %u is present\n", i);
554 rc = ahci_port_init(u16IoBase, i);
555 cPorts--;
556 if (cPorts == 0)
557 break;
558 }
559 i++;
560 }
561
562 return rc;
563}
564
565/**
566 * Init the AHCI driver and detect attached disks.
567 */
568void ahci_init( )
569{
570 Bit16u ebda_seg;
571 Bit16u busdevfn;
572
573 ebda_seg = read_word(0x0040, 0x000E);
574
575 busdevfn = ahci_pci_find_classcode(0x00010601);
576 if (busdevfn != VBOX_AHCI_NO_DEVICE)
577 {
578 Bit8u u8Bus, u8DevFn;
579 Bit8u u8PciCapOff;
580
581 u8Bus = (busdevfn & 0xff00) >> 8;
582 u8DevFn = busdevfn & 0x00ff;
583
584 VBOXAHCI_DEBUG("Found AHCI controller at Bus %u DevFn 0x%x (raw 0x%x)\n", u8Bus, u8DevFn, busdevfn);
585
586 /* Examine the capability list and search for the Serial ATA Capability Register. */
587 u8PciCapOff = ahci_pci_read_config_byte(u8Bus, u8DevFn, PCI_CONFIG_CAP);
588
589 while (u8PciCapOff != 0)
590 {
591 Bit8u u8PciCapId = ahci_pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff);
592
593 VBOXAHCI_DEBUG("Capability ID 0x%x at offset 0x%x found\n", u8PciCapId, u8PciCapOff);
594
595 if (u8PciCapId == PCI_CAP_ID_SATACR)
596 break;
597
598 /* Go on to the next capability. */
599 u8PciCapOff = ahci_pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff + 1);
600 }
601
602 if (u8PciCapOff != 0)
603 {
604 Bit8u u8Rev;
605
606 VBOXAHCI_DEBUG("AHCI controller with SATA Capability register at offset 0x%x found\n", u8PciCapOff);
607
608 /* Advance to the stuff behind the id and next capability pointer. */
609 u8PciCapOff += 2;
610
611 u8Rev = ahci_pci_read_config_byte(u8Bus, u8DevFn, u8PciCapOff);
612 if (u8Rev == 0x10)
613 {
614 /* Read the SATACR1 register and get the bar and offset of the index/data pair register. */
615 Bit8u u8Bar = 0x00;
616 Bit16u u16Off = 0x00;
617 Bit16u u16BarOff = ahci_pci_read_config_word(u8Bus, u8DevFn, u8PciCapOff + 2);
618
619 VBOXAHCI_DEBUG("SATACR1 register contains 0x%x\n", u16BarOff);
620
621 switch (u16BarOff & 0xf)
622 {
623 case 0x04:
624 u8Bar = 0x10;
625 break;
626 case 0x05:
627 u8Bar = 0x14;
628 break;
629 case 0x06:
630 u8Bar = 0x18;
631 break;
632 case 0x07:
633 u8Bar = 0x1c;
634 break;
635 case 0x08:
636 u8Bar = 0x20;
637 break;
638 case 0x09:
639 u8Bar = 0x24;
640 break;
641 case 0x0f:
642 default:
643 /* Reserved or unsupported. */
644 VBOXAHCI_DEBUG("BAR location 0x%x is unsupported\n", u16BarOff & 0xf);
645 }
646
647 /* Get the offset inside the BAR from bits 4:15. */
648 u16Off = (u16BarOff >> 4) * 4;
649
650 if (u8Bar != 0x00)
651 {
652 Bit32u u32Bar = ahci_pci_read_config_dword(u8Bus, u8DevFn, u8Bar);
653
654 VBOXAHCI_DEBUG("BAR at offset 0x%x contains 0x%x\n", u8Bar, u32Bar);
655
656 if ((u32Bar & 0x01) != 0)
657 {
658 int rc;
659 Bit16u u16AhciIoBase = (u32Bar & 0xfff0) + u16Off;
660
661 VBOXAHCI_DEBUG("I/O base is 0x%x\n", u16AhciIoBase);
662 rc = ahci_ctrl_init(u16AhciIoBase);
663 }
664 else
665 VBOXAHCI_DEBUG("BAR is MMIO\n");
666 }
667 }
668 else
669 VBOXAHCI_DEBUG("Invalid revision 0x%x\n", u8Rev);
670 }
671 else
672 VBOXAHCI_DEBUG("AHCI controller without usable Index/Data register pair found\n");
673 }
674 else
675 VBOXAHCI_DEBUG("No AHCI controller found\n");
676}
677
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette