From 34d49541b06f3c24f29214dd162e9a0280a0a57e Mon Sep 17 00:00:00 2001 From: Marcus Overhagen Date: Mon, 27 Apr 2009 22:13:05 +0000 Subject: [PATCH] !!! To use with the ATA stack, change #define ATA_STACK from 0 to 1 !!! Adapted to new ata stack. Works now. Hopefully useable with ide stack, too. Modified to fix the DMA problem introduced with the last change. Since the interrupt is already cleared in the interrupt handler, we can no longer test the interrupt bit in finish_dma(). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30475 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/generic/ide_adapter/ide_adapter.c | 77 ++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/src/add-ons/kernel/generic/ide_adapter/ide_adapter.c b/src/add-ons/kernel/generic/ide_adapter/ide_adapter.c index 14ebe422d6..ab791cea66 100644 --- a/src/add-ons/kernel/generic/ide_adapter/ide_adapter.c +++ b/src/add-ons/kernel/generic/ide_adapter/ide_adapter.c @@ -31,6 +31,8 @@ #define TRACE dprintf +// set this to 1 for the ata stack, or 0 for the ide stack +#define ATA_STACK 0 static ide_for_controller_interface *ide; static device_manager_info *pnp; @@ -188,6 +190,35 @@ ide_adapter_read_pio(ide_adapter_channel_info *channel, uint16 *data, static int32 ide_adapter_inthand(void *arg) { +#if ATA_STACK + ide_adapter_channel_info *channel = (ide_adapter_channel_info *)arg; + pci_device_module_info *pci = channel->pci; + pci_device *device = channel->device; + uint8 statusATA, statusBM; + + // this could be a spurious interrupt, so always read status + // register unconditionally to acknowledge those + statusATA = pci->read_io_8(device, channel->command_block_base + 7); + + if (!channel->dmaing) + return B_UNHANDLED_INTERRUPT; + + // read bus master DMA status to test if the interrupt was + // really generated by our controller + statusBM = pci->read_io_8(device, channel->bus_master_base + + IDE_BM_STATUS_REG); + + if (statusBM & IDE_BM_STATUS_INTERRUPT) { + // clear pending PCI bus master DMA interrupt + pci->write_io_8(device, channel->bus_master_base + IDE_BM_STATUS_REG, + (statusBM & 0xf8) | IDE_BM_STATUS_INTERRUPT); + // signal interrupt to ATA stack + return ide->irq_handler(channel->ide_channel, statusATA); + } else { + return B_UNHANDLED_INTERRUPT; + } + +#else ide_adapter_channel_info *channel = (ide_adapter_channel_info *)arg; pci_device_module_info *pci = channel->pci; pci_device *device = channel->device; @@ -215,6 +246,7 @@ ide_adapter_inthand(void *arg) status = pci->read_io_8(device, channel->command_block_base + 7); return ide->irq_handler(channel->ide_channel, status); +#endif } @@ -274,6 +306,7 @@ ide_adapter_start_dma(ide_adapter_channel_info *channel) + IDE_BM_COMMAND_REG); command |= IDE_BM_COMMAND_START_STOP; + channel->dmaing = true; pci->write_io_8(device, channel->bus_master_base + IDE_BM_COMMAND_REG, @@ -286,6 +319,36 @@ ide_adapter_start_dma(ide_adapter_channel_info *channel) static status_t ide_adapter_finish_dma(ide_adapter_channel_info *channel) { +#if ATA_STACK + pci_device_module_info *pci = channel->pci; + pci_device *device = channel->device; + uint8 command; + uint8 status; + + // read BM status first + status = pci->read_io_8(device, channel->bus_master_base + + IDE_BM_STATUS_REG); + + // stop DMA engine, this also clears IDE_BM_STATUS_ACTIVE + // in the BM status register + command = pci->read_io_8(device, channel->bus_master_base + + IDE_BM_COMMAND_REG); + pci->write_io_8(device, channel->bus_master_base + IDE_BM_COMMAND_REG, + command & ~IDE_BM_COMMAND_START_STOP); + channel->dmaing = false; + + // reset error flag + pci->write_io_8(device, channel->bus_master_base + IDE_BM_STATUS_REG, + status | IDE_BM_STATUS_ERROR); + + if ((status & IDE_BM_STATUS_ACTIVE) != 0) + return B_DEV_DATA_OVERRUN; + + if ((status & IDE_BM_STATUS_ERROR) != 0) + return B_ERROR; + + return B_OK; +#else pci_device_module_info *pci = channel->pci; pci_device *device = channel->device; uint8 command; @@ -310,7 +373,9 @@ ide_adapter_finish_dma(ide_adapter_channel_info *channel) if ((status & IDE_BM_STATUS_ERROR) != 0) return B_ERROR; - +/* + // this doesn't work anymore, because the + // interrupt handler always clears this bit now if ((status & IDE_BM_STATUS_INTERRUPT) == 0) { if ((status & IDE_BM_STATUS_ACTIVE) != 0) { SHOW_ERROR0( 2, "DMA transfer aborted" ); @@ -320,13 +385,14 @@ ide_adapter_finish_dma(ide_adapter_channel_info *channel) SHOW_ERROR0( 2, "DMA transfer: buffer underrun" ); return B_DEV_DATA_UNDERRUN; } - +*/ if ((status & IDE_BM_STATUS_ACTIVE) != 0) { SHOW_ERROR0( 2, "DMA transfer: buffer too large" ); return B_DEV_DATA_OVERRUN; } return B_OK; +#endif } @@ -417,8 +483,15 @@ ide_adapter_init_channel(device_node *node, } TRACE("PCI-IDE: init channel done\n"); + +#if ATA_STACK + // disable interrupts + ide_adapter_write_device_control(channel, ide_devctrl_bit3 | ide_devctrl_nien); +#else // enable interrupts so the channel is ready to run ide_adapter_write_device_control(channel, ide_devctrl_bit3); +#endif + *cookie = channel;