2 Copyright © 1995-2019, The AROS Development Team. All rights reserved.
6 #include <aros/debug.h>
8 #include <proto/exec.h>
10 /* We want all other bases obtained from our base */
13 #include <proto/kernel.h>
14 #include <proto/oop.h>
15 #include <proto/utility.h>
17 #include <hardware/ata.h>
22 #include <utility/tagitem.h>
24 #include "bus_class.h"
25 #include "interface_pio.h"
26 #include "interface_dma.h"
29 AROS_INTH1(ata_PCI_Interrupt
, struct PCIATABusData
*, data
)
36 * The DMA status register indicates all interrupt types, not
37 * just DMA interrupts. However, if there's no DMA port, we have
38 * to rely on the busy flag, which is incompatible with IRQ sharing.
39 * We read ATA status register only once, because reading it tells
40 * the drive to deassert INTRQ.
42 if (data
->bus
->atapb_DMABase
!= 0)
44 port_t dmaStatusPort
= (port_t
)(dma_Status
+ data
->bus
->atapb_DMABase
);
45 UBYTE dmastatus
= inb(dmaStatusPort
);
47 if (!(dmastatus
& DMAF_Interrupt
))
51 * Acknowledge interrupt (note that the DMA interrupt bit should be
52 * cleared for all interrupt types).
53 * Clear DMA interrupt bit before clearing interrupt by reading status
54 * register. Otherwise, it seems that the DMA bit could get set again
55 * for a new interrupt before we clear it, resulting in a missed interrupt.
58 outb(dmastatus
| DMAF_Error
| DMAF_Interrupt
, dmaStatusPort
);
59 status
= inb(data
->bus
->atapb_IOBase
+ ata_Status
);
63 status
= inb(data
->bus
->atapb_IOBase
+ ata_Status
);
65 if (status
& ATAF_BUSY
)
69 data
->ata_HandleIRQ(status
, data
->irqData
);
75 void ata_Raw_Interrupt(struct PCIATABusData
*data
, void *unused
)
77 AROS_INTC1(ata_PCI_Interrupt
, data
);
80 OOP_Object
*PCIATABus__Root__New(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_New
*msg
)
82 struct atapciBase
*base
= cl
->UserData
;
83 struct ata_ProbedBus
*pBus
= (struct ata_ProbedBus
*)GetTagData(aHidd_DriverData
, 0, msg
->attrList
);
84 D(bug("[ATA:PCI:Bus] %s()\n", __PRETTY_FUNCTION__
));
89 o
= (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
92 struct PCIATABusData
*data
= OOP_INST_DATA(cl
, o
);
93 OOP_MethodID mDispose
;
95 D(bug("[ATA:PCI:Bus] %s: instance @ 0x%p\n", __PRETTY_FUNCTION__
, o
));
99 if (data
->bus
->atapb_DMABase
)
102 * FIXME: Currently ata.device does not support shared DMA.
103 * In order to make it work, we disable DMA for secondary channel.
105 if (data
->bus
->atapb_BusNo
> 0)
107 UBYTE dmaStatus
= inb(data
->bus
->atapb_DMABase
+ dma_Status
);
109 if (dmaStatus
& DMAF_Simplex
)
111 bug("[ATA:PCI:Bus] WARNING: Controller only supports "
112 "DMA on one bus at a time. DMAStatus=0x%02X\n", dmaStatus
);
113 bug("[ATA:PCI:Bus] DMA for secondary bus disabled\n");
119 /* We have a DMA controller and will need a buffer */
120 OOP_GetAttr(data
->bus
->atapb_Device
->ref_Device
,
121 aHidd_PCIDevice_Driver
, (IPTR
*)&data
->pciDriver
);
122 data
->dmaBuf
= HIDD_PCIDriver_AllocPCIMem(data
->pciDriver
,
123 (PRD_MAX
+ 1) * 2 * sizeof(struct PRDEntry
));
125 /* If the DMA buffer is not in the first 4G, we cannot do DMA */
126 if ((IPTR
)data
->dmaBuf
!= (ULONG
)(IPTR
)data
->dmaBuf
)
128 HIDD_PCIDriver_FreePCIMem(data
->pciDriver
, data
->dmaBuf
);
131 D(bug("[ATA:PCI:Bus] %s: DMA Buf @ 0x%p\n", __PRETTY_FUNCTION__
, data
->dmaBuf
));
134 if (data
->bus
->atapb_Node
.ln_Type
== ATABUSNODEPRI_PROBED
)
137 * We have a PCI device, install interrupt using portable PCI API.
138 * But do this only if the device is in native mode. In compatibility
139 * mode PCI configuration lies about interrupt number. Experienced
140 * on my Acer AspireOne.
141 * Perhaps this is portability issue but i don't know what to do with
142 * this. Amiga(tm) guys, please check/fix. One possibility is to switch
143 * to native mode here, but i believe in this case i would need to
144 * also set up all I/O regions. On AspireOne only BAR4 is set for IDE
145 * controller. So, also can be bad option. The best case would be if
146 * Amiga(tm) never uses compatibility mode.
147 * Pavel Fedin <pavel_fedin@mail.ru>.
149 struct Interrupt
*pciInt
= AllocMem(sizeof(struct Interrupt
), MEMF_PUBLIC
);
153 pciInt
->is_Node
.ln_Name
= ((struct Node
*)cl
->UserData
)->ln_Name
;
154 pciInt
->is_Node
.ln_Pri
= 0;
155 pciInt
->is_Data
= data
;
156 pciInt
->is_Code
= (APTR
)ata_PCI_Interrupt
;
158 data
->irqHandle
= pciInt
;
159 if (HIDD_PCIDevice_AddInterrupt(data
->bus
->atapb_Device
->ref_Device
, pciInt
))
161 /* Signal structure ownership */
162 data
->bus
->atapb_Node
.ln_Succ
= (struct Node
*)-1;
166 FreeMem(pciInt
, sizeof(struct Interrupt
));
171 /* Legacy device. Use raw system IRQ. */
172 data
->irqHandle
= KrnAddIRQHandler(data
->bus
->atapb_INTLine
, ata_Raw_Interrupt
,
176 data
->bus
->atapb_Node
.ln_Succ
= (struct Node
*)-1;
181 mDispose
= msg
->mID
- moRoot_New
+ moRoot_Dispose
;
182 OOP_DoSuperMethod(cl
, o
, &mDispose
);
187 void DeviceFree(struct PCIDeviceRef
*ref
, struct atapciBase
*base
)
189 HIDD_PCIDevice_Release(ref
->ref_Device
);
190 FreeMem(ref
, sizeof(struct PCIDeviceRef
));
193 void DeviceUnref(struct PCIDeviceRef
*ref
, struct atapciBase
*base
)
201 * Forbid() because dercement and fetch should be atomic.
202 * FIXME: We really need new atomics.
205 count
= --ref
->ref_Count
;
209 DeviceFree(ref
, base
);
212 void PCIATABus__Root__Dispose(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
214 struct atapciBase
*base
= cl
->UserData
;
215 struct PCIATABusData
*data
= OOP_INST_DATA(cl
, o
);
217 D(bug("[ATA:PCI:Bus] %s()\n", __PRETTY_FUNCTION__
));
220 HIDD_PCIDriver_FreePCIMem(data
->pciDriver
, data
->dmaBuf
);
222 if (data
->bus
->atapb_Node
.ln_Type
== ATABUSNODEPRI_PROBED
)
224 HIDD_PCIDevice_RemoveInterrupt(data
->bus
->atapb_Device
->ref_Device
, data
->irqHandle
);
225 FreeMem(data
->irqHandle
, sizeof(struct Interrupt
));
229 KrnRemIRQHandler(data
->irqHandle
);
232 DeviceUnref(data
->bus
->atapb_Device
, base
);
235 OOP_DoSuperMethod(cl
, o
, msg
);
238 void PCIATABus__Root__Get(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_Get
*msg
)
240 struct atapciBase
*base
= cl
->UserData
;
241 struct PCIATABusData
*data
= OOP_INST_DATA(cl
, o
);
244 Hidd_ATABus_Switch(msg
->attrID
, idx
)
246 case aoHidd_ATABus_Use80Wire
:
247 if (data
->bus
->atapb_Device
)
250 * The specification allows to specify per-device flag.
251 * However, both devices sit on the same cable, so we return
252 * TRUE if any of devices support it. We consider only a single
253 * bit because BIOSes may leave zero bits for missing drives.
255 UWORD crmask
= (IOCFG_PCR0
|IOCFG_PCR1
) << (data
->bus
->atapb_BusNo
<< 1);
256 UWORD cfgreg
= HIDD_PCIDevice_ReadConfigWord(data
->bus
->atapb_Device
->ref_Device
, IDE_IO_CFG
);
258 D(bug("[ATA:PCI:Bus] Cable report bits 0x%04X\n", cfgreg
& crmask
));
259 *msg
->storage
= (cfgreg
& crmask
) ? TRUE
: FALSE
;
264 * This is ISA controller.
265 * Of course we can use 80-conductor cable on it. But there will
266 * be neither any way to detect it, nor any improvement. So FALSE.
268 *msg
->storage
= FALSE
;
272 case aoHidd_ATABus_UseDMA
:
273 *msg
->storage
= data
->bus
->atapb_DMABase
? TRUE
: FALSE
;
277 OOP_DoSuperMethod(cl
, o
, &msg
->mID
);
280 void PCIATABus__Root__Set(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_Set
*msg
)
282 struct atapciBase
*base
= cl
->UserData
;
283 struct PCIATABusData
*data
= OOP_INST_DATA(cl
, o
);
284 struct TagItem
*tstate
= msg
->attrList
;
287 while ((tag
= NextTagItem(&tstate
)))
291 Hidd_Bus_Switch(tag
->ti_Tag
, idx
)
293 case aoHidd_Bus_IRQHandler
:
294 data
->ata_HandleIRQ
= (APTR
)tag
->ti_Data
;
297 case aoHidd_Bus_IRQData
:
298 data
->irqData
= (APTR
)tag
->ti_Data
;
304 APTR
PCIATABus__Hidd_ATABus__GetPIOInterface(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
307 struct atapciBase
*base
= cl
->UserData
;
309 struct PCIATABusData
*data
= OOP_INST_DATA(cl
, o
);
310 struct pio_data
*pio
= (struct pio_data
*)OOP_DoSuperMethod(cl
, o
, msg
);
314 pio
->ioBase
= (port_t
)data
->bus
->atapb_IOBase
;
315 pio
->ioAlt
= (port_t
)data
->bus
->atapb_IOAlt
;
321 APTR
PCIATABus__Hidd_ATABus__GetDMAInterface(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
323 struct PCIATABusData
*data
= OOP_INST_DATA(cl
, o
);
324 struct dma_data
*dma
;
326 D(bug("[ATA:PCI:Bus] Hidd_ATABus__GetDMAInterface(0x%p)\n", o
));
327 D(bug("[ATA:PCI:Bus] Hidd_ATABus__GetDMAInterface: cl @ 0x%p\n", cl
));
328 D(bug("[ATA:PCI:Bus] Hidd_ATABus__GetDMAInterface: cl->OOP_DoSuperMethod @ 0x%p\n", (cl
)->cl_DoSuperMethod
));
330 /* If we don't have a DMA buffer, we cannot do DMA */
334 D(bug("[ATA:PCI:Bus] Hidd_ATABus__GetDMAInterface: DMA Buf @ 0x%p\n", data
->dmaBuf
));
335 dma
= (struct dma_data
*)OOP_DoSuperMethod(cl
, o
, msg
);
338 D(bug("[ATA:PCI:Bus] Hidd_ATABus__GetDMAInterface: DMA private data @ 0x%p\n", dma
));
340 dma
->au_DMAPort
= (port_t
)data
->bus
->atapb_DMABase
;
341 dma
->ab_PRD
= data
->dmaBuf
;
343 /* Ensure table does not cross a 4kB boundary (required by VirtualBox,
344 if not by real hardware) */
345 if (0x1000 - ((ULONG
)(IPTR
)dma
->ab_PRD
& 0xfff) <
346 PRD_MAX
* sizeof(struct PRDEntry
))
348 dma
->ab_PRD
= (APTR
)((((IPTR
)dma
->ab_PRD
) + 0xfff) & ~0xfff);
350 D(bug("[ATA:PCI:Bus] Hidd_ATABus__GetDMAInterface: DMA PRD @ 0x%p\n", dma
->ab_PRD
));
353 D(bug("[ATA:PCI:Bus] Hidd_ATABus__GetDMAInterface: Done\n"));
358 BOOL
PCIATABus__Hidd_ATABus__SetXferMode(OOP_Class
*cl
, OOP_Object
*obj
, OOP_Msg msg
)
362 * This code was copied from original ata.device code. There
363 * it was disabled because it is complete rubbish. According
364 * to specifications, these bits in DMA status register are
365 * informational only, and they are set by machine's firmware
366 * if it has successfully configured the drive for DMA operations.
367 * Actually, we should modify controller's timing registers here.
368 * The problem is that these registers are non-standard, and
369 * different controllers have them completely different.
370 * Or, perhaps we should simply check these registers here.
371 * Currently left as it was.
373 struct PCIATABusData
*data
= OOP_INST_DATA(cl
, o
);
375 if (data
->bus
->atapb_DMAPort
)
379 type
= inb(dma_Status
+ unit
->au_DMAPort
) & 0x60;
380 if ((msg
->mode
>= AB_XFER_MDMA0
) && (msg
->mode
<= AB_XFER_UDMA6
))
382 type
|= 1 << (5 + (msg
->UnitNum
& 1));
386 type
&= ~(1 << (5 + (msg
->UnitNum
& 1)));
389 DINIT(bug("[ATA:PCI:Bus] SetXferMode: Trying to apply new DMA (%lx) status: %02lx (unit %ld)\n", unit
->au_DMAPort
, type
, unitNum
));
391 ata_outb(type
, dma_Status
+ unit
->au_DMAPort
);
392 if (type
!= (inb(dma_Status
+ unit
->au_DMAPort
) & 0x60))
394 D(bug("[ATA:PCI:Bus] SetXferMode: Failed to modify DMA state for this device\n"));
398 else if ((msg
->mode
>= AB_XFER_MDMA0
) && (msg
->mode
<= AB_XFER_UDMA6
))
400 /* DMA is not supported, we cannot set DMA modes */
408 void PCIATABus__Hidd_ATABus__Shutdown(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
410 struct PCIATABusData
*data
= OOP_INST_DATA(cl
, o
);
411 port_t dmaBase
= (port_t
)data
->bus
->atapb_DMABase
;
416 outb(inb(dma_Command
+ dmaBase
) & ~DMA_START
, dma_Command
+ dmaBase
);
417 outl(0, dma_PRD
+ dmaBase
);
420 OOP_DoSuperMethod(cl
, o
, msg
);