2 Copyright © 2004-2014, The AROS Development Team. All rights reserved.
5 Desc: Hardware detection routine
11 #define __OOP_NOMETHODBASES__
13 #include <aros/asmcall.h>
14 #include <aros/bootloader.h>
15 #include <aros/debug.h>
16 #include <aros/symbolsets.h>
18 #include <exec/lists.h>
19 #include <exec/rawfmt.h>
20 #include <hardware/ahci.h>
24 #include <proto/bootloader.h>
25 #include <proto/exec.h>
26 #include <proto/oop.h>
30 #include "bus_class.h"
31 #include "interface_pio.h"
32 #include "interface_dma.h"
36 * Currently we support legacy ISA ports only on x86.
37 * This can change only if someone ports AROS to PowerPC
38 * retro-machine like PReP.
41 #define SUPPORT_LEGACY
44 #define SUPPORT_LEGACY
47 #define NAME_BUFFER 128
53 /* static list of io/irqs that we can handle */
59 UBYTE lb_ControllerID
;
64 static const struct ata__legacybus LegacyBuses
[] =
66 {0x1f0, 0x3f4, 14, 0, 0, "ISA IDE0 primary channel" },
67 {0x170, 0x374, 15, 0, 1, "ISA IDE0 secondary channel"},
68 {0x168, 0x36c, 10, 1, 0, "ISA IDE1 primary channel" },
69 {0x1e8, 0x3ec, 11, 1, 1, "ISA IDE1 secondary channel"},
70 { 0, 0, 0, 0, 0, NULL
}
73 #ifdef DO_SATA_HANDOFF
75 /* SATA handoff code needs timer */
77 static struct IORequest
*OpenTimer(void)
79 struct MsgPort
*p
= CreateMsgPort();
83 struct IORequest
*io
= CreateIORequest(p
, sizeof(struct timerequest
));
87 if (0 == OpenDevice("timer.device", UNIT_MICROHZ
, io
, 0))
99 static void CloseTimer(struct IORequest
*tmr
)
103 struct MsgPort
*p
= tmr
->io_Message
.mn_ReplyPort
;
106 DeleteIORequest(tmr
);
111 static void WaitTO(struct IORequest
* tmr
, ULONG secs
, ULONG micro
)
113 tmr
->io_Command
= TR_ADDREQUEST
;
114 ((struct timerequest
*)tmr
)->tr_time
.tv_secs
= secs
;
115 ((struct timerequest
*)tmr
)->tr_time
.tv_micro
= micro
;
124 * collect ALL ata/ide capable devices (including SATA and other) and
125 * spawn concurrent tasks.
127 * This function is growing too large. It will shorten drasticly once this whole mess gets converted into c++
131 AROS_UFH3(void, ata_PCIEnumerator_h
,
132 AROS_UFHA(struct Hook
*, hook
, A0
),
133 AROS_UFHA(OOP_Object
*, Device
, A2
),
134 AROS_UFHA(APTR
, message
,A1
))
138 struct ataBase
*base
= hook
->h_Data
;
140 struct PCIDeviceRef
*devRef
;
141 IPTR ProductID
, VendorID
, DMABase
, DMASize
, INTLine
;
142 IPTR IOBase
, IOAlt
, IOSize
, AltSize
, SubClass
, Interface
;
147 * obtain more or less useful data
149 OOP_GetAttr(Device
, aHidd_PCIDevice_Driver
, (IPTR
*)&Driver
);
150 OOP_GetAttr(Device
, aHidd_PCIDevice_VendorID
, &VendorID
);
151 OOP_GetAttr(Device
, aHidd_PCIDevice_ProductID
, &ProductID
);
152 OOP_GetAttr(Device
, aHidd_PCIDevice_SubClass
, &SubClass
);
153 OOP_GetAttr(Device
, aHidd_PCIDevice_Base4
, &DMABase
);
154 OOP_GetAttr(Device
, aHidd_PCIDevice_Size4
, &DMASize
);
155 OOP_GetAttr(Device
, aHidd_PCIDevice_Interface
, &Interface
);
157 D(bug("[PCI-ATA] ata_PCIEnumerator_h: Found IDE device %04x:%04x\n", VendorID
, ProductID
));
159 /* First check subclass */
160 if ((SubClass
== PCI_SUBCLASS_SCSI
) || (SubClass
== PCI_SUBCLASS_SAS
))
162 D(bug("[PCI-ATA] Unsupported subclass %d\n", SubClass
));
166 owner
= HIDD_PCIDevice_Obtain(Device
, base
->lib
.lib_Node
.ln_Name
);
169 D(bug("[PCI-ATA] Already owned by %s\n", owner
));
173 devRef
= AllocMem(sizeof(struct PCIDeviceRef
), MEMF_ANY
);
176 D(bug("[PCI-ATA] Failed to allocate reference structure\n"));
180 devRef
->ref_Device
= Device
;
181 devRef
->ref_Count
= 0;
184 * SATA controllers may need a special treatment before becoming usable.
185 * The machine's firmware (EFI on Mac) may operate them in native AHCI mode
186 * and not set up legacy mode by itself.
187 * In this case we have to do it ourselves.
188 * This code is based on incomplete ahci.device source code by DissyOfCRN.
189 * CHECKME: In order to work on PPC it uses explicit little-endian I/O,
190 * assuming AHCI register file is always little-endian. Is it correct?
192 if (SubClass
== PCI_SUBCLASS_SATA
)
194 APTR hba_phys
= NULL
;
196 volatile struct ahci_hwhba
*hwhba
;
199 OOP_GetAttr(Device
, aHidd_PCIDevice_Base5
, (IPTR
*)&hba_phys
);
200 OOP_GetAttr(Device
, aHidd_PCIDevice_Size5
, &hba_size
);
202 DSATA(bug("[PCI-ATA] Device %04x:%04x is a SATA device, HBA 0x%p, size 0x%p\n", VendorID
, ProductID
, hba_phys
, hba_size
));
204 hwhba
= HIDD_PCIDriver_MapPCI(Driver
, hba_phys
, hba_size
);
205 DSATA(bug("[PCI-ATA] Mapped at 0x%p\n", hwhba
));
209 DSATA(bug("[PCI-ATA] Mapping failed, device will be ignored\n"));
210 DeviceFree(devRef
, base
);
214 cap
= mmio_inl_le(&hwhba
->cap
);
215 ghc
= mmio_inl_le(&hwhba
->ghc
);
216 DSATA(bug("[PCI-ATA] Capabilities: 0x%08X, host control: 0x%08X\n", cap
, ghc
));
219 * Some hardware may report GHC_AE to be zero, together with CAP_SAM set (indicating
220 * that the device doesn't support legacy IDE registers). Seems to be spec violation
221 * (the AHCI specification says that in this cases GHC_AE is read-only bit which is
223 * Attempting to drive such a hardware causes ata.device to freeze.
224 * This effect has been observed on Marvel 9172 controller (and some other HW,
225 * according to user reports, but nobody has ever provided a debug log).
229 DSATA(bug("[PCI-ATA] Legacy mode is not supported, device will be ignored\n"));
231 HIDD_PCIDriver_UnmapPCI(Driver
, hba_phys
, hba_size
);
232 DeviceFree(devRef
, base
);
238 DSATA(bug("[PCI-ATA] AHCI enabled\n"));
241 * This is ATA driver, not SATA driver, so i'd like to keep SATA-specific code
242 * at a minimum. None of tests revealed a real need for BIOS handoff, no BIOS
243 * was discovered to use controllers in SMI mode.
244 * However, if on some machine we have problems, we can try
247 #ifdef DO_SATA_HANDOFF
248 ULONG version
= mmio_inl_le(&hwhba
->vs
);
249 ULONG cap2
= mmio_inl_le(&hwhba
->cap2
);
251 DSATA(bug("[PCI-ATA] Version: 0x%08X, Cap2: 0x%08X\n", version
, cap2
));
253 if ((version
>= AHCI_VERSION_1_20
) && (cap2
&& CAP2_BOH
))
257 DSATA(bug("[PCI-ATA] HBA supports BIOS/OS handoff\n"));
259 bohc
= mmio_inl_le(&hwhba
->bohc
);
260 if (bohc
&& BOHC_BOS
)
262 struct IORequest
*timereq
;
264 DSATA(bug("[PCI-ATA] Device owned by BIOS, performing handoff\n"));
267 * We need timer.device in order to perform delays.
268 * TODO: in ata_InitBus() it will be opened and closed again.
269 * This is not optimal, it could be opened and closed just once.
271 timereq
= OpenTimer(base
);
274 DSATA(bug("[PCI-ATA] Failed to open timer, can't perform handoff. Device will be ignored\n"));
276 HIDD_PCIDriver_UnmapPCI(Driver
, hba_phys
, hba_size
);
277 DeviceFree(devRef
, base
);
281 mmio_outl_le(bohc
| BOHC_OOS
, &hwhba
->bohc
);
282 /* Spin on BOHC_BOS bit FIXME: Possible dead lock. No maximum time given on AHCI1.3 specs... */
283 while (mmio_inl_le(&hwhba
->bohc
) & BOHC_BOS
);
285 WaitTO(timereq
, 0, 25000);
286 /* If after 25ms BOHC_BB bit is still set give bios a minimum of 2 seconds more time to run */
288 if (mmio_inl_le(&hwhba
->bohc
) & BOHC_BB
)
290 DSATA(bug("[PCI-ATA] Delayed handoff, waiting...\n"));
291 ata_WaitTO(timereq
, 2, 0);
294 DSATA(bug("[PCI-ATA] Handoff done\n"));
299 /* This resets GHC_AE bit, disabling AHCI */
300 mmio_outl_le(0, &hwhba
->ghc
);
303 HIDD_PCIDriver_UnmapPCI(Driver
, (APTR
)hwhba
, hba_size
);
307 * we can have up to two buses assigned to this device
309 for (x
= 0; devRef
!= NULL
&& x
< MAX_DEVICEBUSES
; x
++)
311 BYTE basePri
= ATABUSNODEPRI_PROBED
;
314 * obtain I/O bases and interrupt line
316 if ((Interface
& (1 << (x
<< 1))) || SubClass
!= PCI_SUBCLASS_IDE
)
321 OOP_GetAttr(Device
, aHidd_PCIDevice_Base0
, &IOBase
);
322 OOP_GetAttr(Device
, aHidd_PCIDevice_Size0
, &IOSize
);
323 OOP_GetAttr(Device
, aHidd_PCIDevice_Base1
, &IOAlt
);
324 OOP_GetAttr(Device
, aHidd_PCIDevice_Size1
, &AltSize
);
328 OOP_GetAttr(Device
, aHidd_PCIDevice_Base2
, &IOBase
);
329 OOP_GetAttr(Device
, aHidd_PCIDevice_Size2
, &IOSize
);
330 OOP_GetAttr(Device
, aHidd_PCIDevice_Base3
, &IOAlt
);
331 OOP_GetAttr(Device
, aHidd_PCIDevice_Size3
, &AltSize
);
334 OOP_GetAttr(Device
, aHidd_PCIDevice_INTLine
, &INTLine
);
336 else if (LegacyBuses
[base
->legacycount
].lb_ControllerID
== 0)
340 OOP_GetAttr(Driver
, aHidd_PCIDriver_IOBase
, &isa_io_base
);
341 D(bug("[PCI-ATA] Device using Legacy-Bus IOPorts @ 0x%p\n", isa_io_base
));
343 IOBase
= LegacyBuses
[base
->legacycount
].lb_Port
+ isa_io_base
;
344 IOAlt
= LegacyBuses
[base
->legacycount
].lb_Alt
+ isa_io_base
;
345 INTLine
= LegacyBuses
[base
->legacycount
].lb_IRQ
;
346 basePri
= ATABUSNODEPRI_PROBEDLEGACY
;
348 AltSize
= RANGESIZE1
;
354 D(bug("[PCI-ATA] Ran out of legacy buses\n"));
358 if (IOBase
!= 0 && IOSize
== RANGESIZE0
&& AltSize
== RANGESIZE1
&&
359 (DMASize
>= DMASIZE
|| DMABase
== 0 || SubClass
== PCI_SUBCLASS_IDE
))
361 struct ata_ProbedBus
*probedbus
;
365 D(bug("[PCI-ATA] ata_PCIEnumerator_h: Adding Bus %d - IRQ %d, IO: %x:%x, DMA: %x\n",
366 x
, INTLine
, IOBase
, IOAlt
, DMABase
));
368 OOP_GetAttr(Device
, aHidd_PCIDevice_SubClassDesc
, (IPTR
*)&str
[0]);
369 str
[1] = x
? "secondary" : "primary";
370 len
= 14 + strlen(str
[0]) + strlen(str
[1]);
372 probedbus
= AllocVec(sizeof(struct ata_ProbedBus
) + len
, MEMF_ANY
);
375 IPTR dmaBase
= DMABase
? DMABase
+ (x
<< 3) : 0;
376 STRPTR name
= (char *)probedbus
+ sizeof(struct ata_ProbedBus
);
378 RawDoFmt("PCI %s %s channel", (RAWARG
)str
, RAWFMTFUNC_STRING
, name
);
380 probedbus
->atapb_Node
.ln_Name
= name
;
381 probedbus
->atapb_Node
.ln_Type
= basePri
;
382 probedbus
->atapb_Node
.ln_Pri
= basePri
- (base
->ata__buscount
++);
383 probedbus
->atapb_Device
= devRef
;
384 probedbus
->atapb_Vendor
= VendorID
;
385 probedbus
->atapb_Product
= ProductID
;
386 probedbus
->atapb_BusNo
= x
;
387 probedbus
->atapb_IOBase
= IOBase
;
388 probedbus
->atapb_IOAlt
= IOAlt
;
389 probedbus
->atapb_INTLine
= INTLine
;
390 probedbus
->atapb_DMABase
= dmaBase
;
393 Enqueue((struct List
*)&base
->probedbuses
, &probedbus
->atapb_Node
);
395 OOP_SetAttrsTags(Device
, aHidd_PCIDevice_isIO
, TRUE
,
396 aHidd_PCIDevice_isMaster
, DMABase
!= 0,
401 if (!devRef
->ref_Count
)
403 DeviceFree(devRef
, base
);
411 static CONST_STRPTR pciInterfaceIDs
[] =
419 /* We need no attributes for IID_Hidd_PCI, only methods */
420 #define ATTR_OFFSET 1
422 static const struct TagItem Requirements
[] =
424 {tHidd_PCI_Class
, PCI_CLASS_MASSSTORAGE
},
429 * The manner in which this code is written can look a little bit overcomplicated.
430 * However it's just experimental attempt to write hardware scan routine which
431 * can be run more than once, and is hotplug-aware.
432 * In future this may assist implementation of "Rescan devices" functionality
433 * in SysExplorer (for example). This will provide a possibility to load and unload
434 * device drivers on the fly.
435 * For now it's just experiment... Don't pay much attention please. :)
437 static int ata_pci_Scan(struct ataBase
*base
)
439 OOP_Object
*ata
= OOP_NewObject(NULL
, CLID_HW_ATA
, NULL
);
441 struct ata_ProbedBus
*probedbus
;
443 #ifdef SUPPORT_LEGACY
444 BOOL scanlegacy
= TRUE
;
447 /* First make sure that ATA subsystem is in place */
451 /* Prepare lists for probed/found ide buses */
452 NEWLIST(&base
->probedbuses
);
453 base
->ata__buscount
= 0;
454 base
->legacycount
= 0;
456 /* Obtain command line parameters */
457 BootLoaderBase
= OpenResource("bootloader.resource");
458 D(bug("[PCI-ATA] BootloaderBase = %p\n", BootLoaderBase
));
459 if (BootLoaderBase
!= NULL
)
464 list
= (struct List
*)GetBootInfo(BL_Args
);
467 ForeachNode(list
, node
)
469 if (strncmp(node
->ln_Name
, "ATA=", 4) == 0)
471 const char *cmdline
= &node
->ln_Name
[4];
473 if (strstr(cmdline
, "nopci"))
475 D(bug("[PCI-ATA] Disabling PCI device scan\n"));
478 #ifdef SUPPORT_LEGACY
479 if (strstr(cmdline
, "nolegacy"))
481 D(bug("[PCI-ATA] Disabling Legacy ports\n"));
485 if (strstr(cmdline
, "off"))
487 D(bug("[PCI-ATA] Disabling all ATA devices\n"));
488 #ifdef SUPPORT_LEGACY
499 D(bug("[PCI-ATA] ata_Scan: Enumerating devices\n"));
504 * Attempt to get PCI subsytem object.
505 * If this fails, PCI isn't there. But it's not fatal for us.
507 OOP_Object
*pci
= OOP_NewObject(NULL
, CLID_Hidd_PCI
, NULL
);
511 struct Hook FindHook
=
513 .h_Entry
= (IPTR (*)())ata_PCIEnumerator_h
,
517 D(bug("[PCI-ATA] ata_Scan: Checking for supported PCI devices ..\n"));
520 * Obtain PCI attribute and method bases only once.
521 * We perform no result checks, because since PCI subsystem is in place,
522 * its attribute and method bases are also 100% in place.
524 if (!base
->PCIDeviceAttrBase
)
526 OOP_ObtainAttrBasesArray(&base
->PCIDeviceAttrBase
, &pciInterfaceIDs
[ATTR_OFFSET
]);
527 OOP_ObtainMethodBasesArray(&base
->PCIMethodBase
, pciInterfaceIDs
);
530 HIDD_PCI_EnumDevices(pci
, &FindHook
, Requirements
);
534 #ifdef SUPPORT_LEGACY
537 UBYTE n
= base
->legacycount
;
539 D(bug("[PCI-ATA] ata_Scan: Adding Remaining Legacy-Buses\n"));
541 while (LegacyBuses
[n
].lb_Port
)
543 probedbus
= AllocVec(sizeof(struct ata_ProbedBus
), MEMF_ANY
);
546 probedbus
->atapb_Node
.ln_Name
= (STRPTR
)LegacyBuses
[n
].lb_Name
;
547 probedbus
->atapb_Node
.ln_Type
= ATABUSNODEPRI_LEGACY
;
548 probedbus
->atapb_Node
.ln_Pri
= ATABUSNODEPRI_LEGACY
- (base
->ata__buscount
++);
549 probedbus
->atapb_Device
= NULL
;
550 probedbus
->atapb_Vendor
= 0;
551 probedbus
->atapb_Product
= 0;
552 probedbus
->atapb_BusNo
= LegacyBuses
[n
].lb_Bus
;
553 probedbus
->atapb_IOBase
= LegacyBuses
[n
].lb_Port
;
554 probedbus
->atapb_IOAlt
= LegacyBuses
[n
].lb_Alt
;
555 probedbus
->atapb_INTLine
= LegacyBuses
[n
].lb_IRQ
;
556 probedbus
->atapb_DMABase
= 0;
558 D(bug("[PCI-ATA] ata_Scan: Adding Legacy Bus - IO: %x:%x\n",
559 probedbus
->atapb_IOBase
, probedbus
->atapb_IOAlt
));
561 Enqueue((struct List
*)&base
->probedbuses
, &probedbus
->atapb_Node
);
568 D(bug("[PCI-ATA] ata_Scan: Registering Probed Buses..\n"));
570 HWBase
= OOP_GetMethodID(IID_HW
, 0);
571 while ((probedbus
= (struct ata_ProbedBus
*)RemHead((struct List
*)&base
->probedbuses
)) != NULL
)
573 struct TagItem attrs
[] =
575 {aHidd_HardwareName
, (IPTR
)probedbus
->atapb_Node
.ln_Name
},
576 {aHidd_Producer
, probedbus
->atapb_Vendor
},
577 {aHidd_Product
, probedbus
->atapb_Product
},
578 {aHidd_DriverData
, (IPTR
)probedbus
},
579 {aHidd_ATABus_PIODataSize
, sizeof(struct pio_data
) },
580 {aHidd_ATABus_BusVectors
, (IPTR
)bus_FuncTable
},
581 {aHidd_ATABus_PIOVectors
, (IPTR
)pio_FuncTable
},
582 {aHidd_ATABus_DMADataSize
, sizeof(struct dma_data
) },
583 {aHidd_ATABus_DMAVectors
, (IPTR
)dma_FuncTable
},
585 * Legacy ISA controllers have no other way to detect their
586 * presence. Do not confuse the user with phantom devices.
588 {aHidd_ATABus_KeepEmpty
, probedbus
->atapb_Node
.ln_Type
== ATABUSNODEPRI_LEGACY
595 * We use this field as ownership indicator.
596 * The trick is that HW_AddDriver() fails if either object creation fails
597 * or subsystem-side setup fails. In the latter case our object will be
599 * We need to know whether OOP_DisposeObject() or we should deallocate
600 * this structure on failure.
602 probedbus
->atapb_Node
.ln_Succ
= NULL
;
604 bus
= HW_AddDriver(ata
, base
->busClass
, attrs
);
607 D(bug("[PCI-ATA] Failed to create object for device %04X:%04X - IRQ %d, IO: %x:%x, DMA: %x\n",
608 probedbus
->atapb_Vendor
, probedbus
->atapb_Product
, probedbus
->atapb_INTLine
,
609 probedbus
->atapb_IOBase
, probedbus
->atapb_IOAlt
, probedbus
->atapb_DMABase
));
612 * Free the structure only upon object creation failure!
613 * In case of success it becomes owned by the driver object!
615 if (!probedbus
->atapb_Node
.ln_Succ
)
617 DeviceUnref(probedbus
->atapb_Device
, base
);
626 ADD2INITLIB(ata_pci_Scan
, 30)