2 Copyright © 1995-2016, The AROS Development Team. All rights reserved.
6 #include <aros/debug.h>
7 #include <hardware/ata.h>
11 #include <utility/tagitem.h>
12 #include <proto/exec.h>
13 #include <proto/kernel.h>
14 #include <proto/oop.h>
15 #include <proto/utility.h>
17 #include "bus_class.h"
18 #include "interface_pio.h"
19 #include "interface_dma.h"
22 AROS_INTH1(ata_PCI_Interrupt
, struct ATA_BusData
*, data
)
29 * The DMA status register indicates all interrupt types, not
30 * just DMA interrupts. However, if there's no DMA port, we have
31 * to rely on the busy flag, which is incompatible with IRQ sharing.
32 * We read ATA status register only once, because reading it tells
33 * the drive to deassert INTRQ.
35 if (data
->bus
->atapb_DMABase
!= 0)
37 port_t dmaStatusPort
= dma_Status
+ data
->bus
->atapb_DMABase
;
38 UBYTE dmastatus
= inb(dmaStatusPort
);
40 if (!(dmastatus
& DMAF_Interrupt
))
44 * Acknowledge interrupt (note that the DMA interrupt bit should be
45 * cleared for all interrupt types).
46 * Clear DMA interrupt bit before clearing interrupt by reading status
47 * register. Otherwise, it seems that the DMA bit could get set again
48 * for a new interrupt before we clear it, resulting in a missed interrupt.
51 outb(dmastatus
| DMAF_Error
| DMAF_Interrupt
, dmaStatusPort
);
52 status
= inb(data
->bus
->atapb_IOBase
+ ata_Status
);
56 status
= inb(data
->bus
->atapb_IOBase
+ ata_Status
);
58 if (status
& ATAF_BUSY
)
62 data
->ata_HandleIRQ(status
, data
->irqData
);
68 void ata_Raw_Interrupt(struct ATA_BusData
*data
, void *unused
)
70 AROS_INTC1(ata_PCI_Interrupt
, data
);
73 OOP_Object
*PCIATA__Root__New(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_New
*msg
)
75 o
= (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, &msg
->mID
);
78 struct ataBase
*base
= cl
->UserData
;
79 struct ATA_BusData
*data
= OOP_INST_DATA(cl
, o
);
80 OOP_MethodID mDispose
;
82 /* No check because we always supply this */
83 data
->bus
= (struct ata_ProbedBus
*)GetTagData(aHidd_DriverData
, 0, msg
->attrList
);
85 if (data
->bus
->atapb_DMABase
)
88 * FIXME: Currently ata.device does not support shared DMA.
89 * In order to make it working, we disable DMA for secondary channel.
91 if (data
->bus
->atapb_BusNo
> 0)
93 UBYTE dmaStatus
= inb(data
->bus
->atapb_DMABase
+ dma_Status
);
95 if (dmaStatus
& DMAF_Simplex
)
97 bug("[PCI-ATA] WARNING: Controller only supports "
98 "DMA on one bus at a time. DMAStatus=0x%02X\n", dmaStatus
);
99 bug("[PCI-ATA] DMA for secondary bus disabled\n");
105 /* We have a DMA controller and will need a buffer */
106 OOP_GetAttr(data
->bus
->atapb_Device
->ref_Device
,
107 aHidd_PCIDevice_Driver
, (IPTR
*)&data
->pciDriver
);
108 data
->dmaBuf
= HIDD_PCIDriver_AllocPCIMem(data
->pciDriver
,
109 (PRD_MAX
+ 1) * 2 * sizeof(struct PRDEntry
));
112 if (data
->bus
->atapb_Node
.ln_Type
== ATABUSNODEPRI_PROBED
)
115 * We have a PCI device, install interrupt using portable PCI API.
116 * But do this only if the device is in native mode. In compatibility
117 * mode PCI configuration lies about interrupt number. Experienced
118 * on my Acer AspireOne.
119 * Perhaps this is portability issue but i don't know what to do with
120 * this. Amiga(tm) guys, please check/fix. One possibility is to switch
121 * to native mode here, but i believe in this case i would need to
122 * also set up all I/O regions. On AspireOne only BAR4 is set for IDE
123 * controller. So, also can be bad option. The best case would be if
124 * Amiga(tm) never uses compatibility mode.
125 * Pavel Fedin <pavel_fedin@mail.ru>.
127 struct Interrupt
*pciInt
= AllocMem(sizeof(struct Interrupt
), MEMF_PUBLIC
);
131 pciInt
->is_Node
.ln_Name
= ((struct Node
*)cl
->UserData
)->ln_Name
;
132 pciInt
->is_Node
.ln_Pri
= 0;
133 pciInt
->is_Data
= data
;
134 pciInt
->is_Code
= (APTR
)ata_PCI_Interrupt
;
136 data
->irqHandle
= pciInt
;
137 if (HIDD_PCIDevice_AddInterrupt(data
->bus
->atapb_Device
->ref_Device
, pciInt
))
139 /* Signal structure ownership */
140 data
->bus
->atapb_Node
.ln_Succ
= (struct Node
*)-1;
144 FreeMem(pciInt
, sizeof(struct Interrupt
));
149 /* Legacy device. Use raw system IRQ. */
150 data
->irqHandle
= KrnAddIRQHandler(data
->bus
->atapb_INTLine
, ata_Raw_Interrupt
,
154 data
->bus
->atapb_Node
.ln_Succ
= (struct Node
*)-1;
159 mDispose
= msg
->mID
- moRoot_New
+ moRoot_Dispose
;
160 OOP_DoSuperMethod(cl
, o
, &mDispose
);
165 void DeviceFree(struct PCIDeviceRef
*ref
, struct ataBase
*base
)
167 HIDD_PCIDevice_Release(ref
->ref_Device
);
168 FreeMem(ref
, sizeof(struct PCIDeviceRef
));
171 void DeviceUnref(struct PCIDeviceRef
*ref
, struct ataBase
*base
)
179 * Forbid() because dercement and fetch should be atomic.
180 * FIXME: We really need new atomics.
183 count
= --ref
->ref_Count
;
187 DeviceFree(ref
, base
);
190 void PCIATA__Root__Dispose(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
192 struct ataBase
*base
= cl
->UserData
;
193 struct ATA_BusData
*data
= OOP_INST_DATA(cl
, o
);
196 HIDD_PCIDriver_FreePCIMem(data
->pciDriver
, data
->dmaBuf
);
198 if (data
->bus
->atapb_Node
.ln_Type
== ATABUSNODEPRI_PROBED
)
200 HIDD_PCIDevice_RemoveInterrupt(data
->bus
->atapb_Device
->ref_Device
, data
->irqHandle
);
201 FreeMem(data
->irqHandle
, sizeof(struct Interrupt
));
205 KrnRemIRQHandler(data
->irqHandle
);
208 DeviceUnref(data
->bus
->atapb_Device
, base
);
211 OOP_DoSuperMethod(cl
, o
, msg
);
214 void PCIATA__Root__Get(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_Get
*msg
)
216 struct ataBase
*base
= cl
->UserData
;
217 struct ATA_BusData
*data
= OOP_INST_DATA(cl
, o
);
220 Hidd_ATABus_Switch(msg
->attrID
, idx
)
222 case aoHidd_ATABus_Use80Wire
:
223 if (data
->bus
->atapb_Device
)
226 * The specification allows to specify per-device flag.
227 * However, both devices sit on the same cable, so we return
228 * TRUE if any of devices support it. We consider only a single
229 * bit because BIOSes may leave zero bits for missing drives.
231 UWORD crmask
= (IOCFG_PCR0
|IOCFG_PCR1
) << (data
->bus
->atapb_BusNo
<< 1);
232 UWORD cfgreg
= HIDD_PCIDevice_ReadConfigWord(data
->bus
->atapb_Device
->ref_Device
, IDE_IO_CFG
);
234 D(bug("[PCI-ATA] Cable report bits 0x%04X\n", cfgreg
& crmask
));
235 *msg
->storage
= (cfgreg
& crmask
) ? TRUE
: FALSE
;
240 * This is ISA controller.
241 * Of course we can use 80-conductor cable on it. But there will
242 * be neither any way to detect it, nor any improvement. So FALSE.
244 *msg
->storage
= FALSE
;
248 case aoHidd_ATABus_UseDMA
:
249 *msg
->storage
= data
->bus
->atapb_DMABase
? TRUE
: FALSE
;
253 OOP_DoSuperMethod(cl
, o
, &msg
->mID
);
256 void PCIATA__Root__Set(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_Set
*msg
)
258 struct ataBase
*base
= cl
->UserData
;
259 struct ATA_BusData
*data
= OOP_INST_DATA(cl
, o
);
260 struct TagItem
*tstate
= msg
->attrList
;
263 while ((tag
= NextTagItem(&tstate
)))
267 Hidd_ATABus_Switch(tag
->ti_Tag
, idx
)
269 case aoHidd_ATABus_IRQHandler
:
270 data
->ata_HandleIRQ
= (APTR
)tag
->ti_Data
;
273 case aoHidd_ATABus_IRQData
:
274 data
->irqData
= (APTR
)tag
->ti_Data
;
280 APTR
PCIATA__Hidd_ATABus__GetPIOInterface(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
282 struct ATA_BusData
*data
= OOP_INST_DATA(cl
, o
);
283 struct pio_data
*pio
= (struct pio_data
*)OOP_DoSuperMethod(cl
, o
, msg
);
287 pio
->ioBase
= data
->bus
->atapb_IOBase
;
288 pio
->ioAlt
= data
->bus
->atapb_IOAlt
;
294 APTR
PCIATA__Hidd_ATABus__GetDMAInterface(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
296 struct ATA_BusData
*data
= OOP_INST_DATA(cl
, o
);
297 struct dma_data
*dma
;
299 /* If we don't have a DMA buffer, we cannot do DMA */
303 /* If the DMA buffer is not in the first 4G, we cannot do DMA */
304 if ((IPTR
)data
->dmaBuf
!= (ULONG
)(IPTR
)data
->dmaBuf
)
307 dma
= (struct dma_data
*)OOP_DoSuperMethod(cl
, o
, msg
);
310 dma
->au_DMAPort
= data
->bus
->atapb_DMABase
;
311 dma
->ab_PRD
= data
->dmaBuf
;
313 /* Ensure table does not cross a 4kB boundary (required by VirtualBox,
314 if not by real hardware) */
315 if (0x1000 - ((ULONG
)(IPTR
)dma
->ab_PRD
& 0xfff) <
316 PRD_MAX
* sizeof(struct PRDEntry
))
318 dma
->ab_PRD
= (APTR
)((((IPTR
)dma
->ab_PRD
) + 0xfff) & ~0xfff);
325 BOOL
PCIATA__Hidd_ATABus__SetXferMode(OOP_Class
*cl
, OOP_Object
*obj
, OOP_Msg msg
)
329 * This code was copied from original ata.device code. There
330 * it was disabled because it is complete rubbish. According
331 * to specifications, these bits in DMA status register are
332 * informational only, and they are set by machine's firmware
333 * if it has successfully configured the drive for DMA operations.
334 * Actually, we should modify controller's timing registers here.
335 * The problem is that these registers are non-standard, and
336 * different controllers have them completely different.
337 * Or, perhaps we should simply check these registers here.
338 * Currently left as it was.
340 struct ATA_BusData
*data
= OOP_INST_DATA(cl
, o
);
342 if (data
->bus
->atapb_DMAPort
)
346 type
= inb(dma_Status
+ unit
->au_DMAPort
) & 0x60;
347 if ((msg
->mode
>= AB_XFER_MDMA0
) && (msg
->mode
<= AB_XFER_UDMA6
))
349 type
|= 1 << (5 + (msg
->UnitNum
& 1));
353 type
&= ~(1 << (5 + (msg
->UnitNum
& 1)));
356 DINIT(bug("[PCI-ATA] SetXferMode: Trying to apply new DMA (%lx) status: %02lx (unit %ld)\n", unit
->au_DMAPort
, type
, unitNum
));
358 ata_outb(type
, dma_Status
+ unit
->au_DMAPort
);
359 if (type
!= (inb(dma_Status
+ unit
->au_DMAPort
) & 0x60))
361 D(bug("[PCI-ATA] SetXferMode: Failed to modify DMA state for this device\n"));
365 else if ((msg
->mode
>= AB_XFER_MDMA0
) && (msg
->mode
<= AB_XFER_UDMA6
))
367 /* DMA is not supported, we cannot set DMA modes */
375 void PCIATA__Hidd_ATABus__Shutdown(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
377 struct ATA_BusData
*data
= OOP_INST_DATA(cl
, o
);
378 port_t dmaBase
= data
->bus
->atapb_DMABase
;
383 outb(inb(dma_Command
+ dmaBase
) & ~DMA_START
, dma_Command
+ dmaBase
);
384 outl(0, dma_PRD
+ dmaBase
);
387 OOP_DoSuperMethod(cl
, o
, msg
);