revert between 56095 -> 55830 in arch
[AROS.git] / rom / hidds / ata_pci / bus_class.c
blob80d7a7d8b5d87058a4476919e2e78b3b47942dc3
1 /*
2 Copyright © 1995-2019, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <aros/debug.h>
8 #include <proto/exec.h>
10 /* We want all other bases obtained from our base */
11 #define __NOLIBBASE__
13 #include <proto/kernel.h>
14 #include <proto/oop.h>
15 #include <proto/utility.h>
17 #include <hardware/ata.h>
18 #include <hidd/bus.h>
19 #include <hidd/ata.h>
20 #include <hidd/pci.h>
21 #include <oop/oop.h>
22 #include <utility/tagitem.h>
24 #include "bus_class.h"
25 #include "interface_pio.h"
26 #include "interface_dma.h"
27 #include "pci.h"
29 AROS_INTH1(ata_PCI_Interrupt, struct PCIATABusData *, data)
31 AROS_INTFUNC_INIT
33 UBYTE status;
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))
48 return FALSE;
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.
56 * Neil
58 outb(dmastatus | DMAF_Error | DMAF_Interrupt, dmaStatusPort);
59 status = inb(data->bus->atapb_IOBase + ata_Status);
61 else
63 status = inb(data->bus->atapb_IOBase + ata_Status);
65 if (status & ATAF_BUSY)
66 return FALSE;
69 data->ata_HandleIRQ(status, data->irqData);
70 return TRUE;
72 AROS_INTFUNC_EXIT
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__));
86 if (!pBus)
87 return NULL;
89 o = (OOP_Object *)OOP_DoSuperMethod(cl, o, (OOP_Msg)msg);
90 if (o)
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));
97 data->bus = pBus;
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");
115 goto nodma;
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);
129 data->dmaBuf = NULL;
131 D(bug("[ATA:PCI:Bus] %s: DMA Buf @ 0x%p\n", __PRETTY_FUNCTION__, data->dmaBuf));
133 nodma:
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);
151 if (pciInt)
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;
163 return o;
166 FreeMem(pciInt, sizeof(struct Interrupt));
169 else
171 /* Legacy device. Use raw system IRQ. */
172 data->irqHandle = KrnAddIRQHandler(data->bus->atapb_INTLine, ata_Raw_Interrupt,
173 data, NULL);
174 if (data->irqHandle)
176 data->bus->atapb_Node.ln_Succ = (struct Node *)-1;
177 return o;
181 mDispose = msg->mID - moRoot_New + moRoot_Dispose;
182 OOP_DoSuperMethod(cl, o, &mDispose);
184 return NULL;
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)
195 ULONG count;
197 if (!ref)
198 return;
201 * Forbid() because dercement and fetch should be atomic.
202 * FIXME: We really need new atomics.
204 Forbid();
205 count = --ref->ref_Count;
206 Permit();
208 if (!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__));
219 if (data->dmaBuf)
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));
227 else
229 KrnRemIRQHandler(data->irqHandle);
232 DeviceUnref(data->bus->atapb_Device, base);
233 FreeVec(data->bus);
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);
242 ULONG idx;
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;
261 else
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;
270 return;
272 case aoHidd_ATABus_UseDMA:
273 *msg->storage = data->bus->atapb_DMABase ? TRUE : FALSE;
274 return;
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;
285 struct TagItem *tag;
287 while ((tag = NextTagItem(&tstate)))
289 ULONG idx;
291 Hidd_Bus_Switch(tag->ti_Tag, idx)
293 case aoHidd_Bus_IRQHandler:
294 data->ata_HandleIRQ = (APTR)tag->ti_Data;
295 break;
297 case aoHidd_Bus_IRQData:
298 data->irqData = (APTR)tag->ti_Data;
299 break;
304 APTR PCIATABus__Hidd_ATABus__GetPIOInterface(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
306 #if (0)
307 struct atapciBase *base = cl->UserData;
308 #endif
309 struct PCIATABusData *data = OOP_INST_DATA(cl, o);
310 struct pio_data *pio = (struct pio_data *)OOP_DoSuperMethod(cl, o, msg);
312 if (pio)
314 pio->ioBase = (port_t)data->bus->atapb_IOBase;
315 pio->ioAlt = (port_t)data->bus->atapb_IOAlt;
318 return pio;
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 */
331 if (!data->dmaBuf)
332 return NULL;
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);
336 if (dma)
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"));
355 return dma;
358 BOOL PCIATABus__Hidd_ATABus__SetXferMode(OOP_Class *cl, OOP_Object *obj, OOP_Msg msg)
360 #if 0
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)
377 UBYTE type;
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));
384 else
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"));
395 return FALSE;
398 else if ((msg->mode >= AB_XFER_MDMA0) && (msg->mode <= AB_XFER_UDMA6))
400 /* DMA is not supported, we cannot set DMA modes */
401 return FALSE;
403 #endif
405 return TRUE;
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;
413 if (dmaBase)
415 /* Shut down DMA */
416 outb(inb(dma_Command + dmaBase) & ~DMA_START, dma_Command + dmaBase);
417 outl(0, dma_PRD + dmaBase);
420 OOP_DoSuperMethod(cl, o, msg);