📄 ide-ep93xx.c
字号:
*table++ = cur_addr; xcount = bcount & 0xffff; if (xcount == 0x0000) { /* * Most chipsets correctly interpret a * length of 0x0000 as 64KB, but at * least one (e.g. CS5530) * misinterprets it as zero (!). So * here we break the 64KB entry into * two 32KB entries instead. */ if (count++ >= PRD_ENTRIES) { printk("%s: DMA table too small\n", drive->name); goto use_pio_instead; } *table++ = 0x8000; *table++ = cur_addr + 0x8000; xcount = 0x8000; } *table++ = xcount; cur_addr += bcount; cur_len -= bcount; } } sg++; i--; } if (count) { *--table |= 0x80000000; return count; } printk("%s: empty DMA table?\n", drive->name);use_pio_instead: /* * Revert to PIO for this request. */ HWIF(drive)->sg_dma_active = 0; return 0;}/***************************************************************************** * * ide_release_dma() * * This function releases the memory allocated for the scatter gather list * and for the dma table, and frees the dma channel. * ****************************************************************************/static voidep93xx_ide_release_dma(ide_hwif_t *hwif){ DPRINTK("%s: ep93xx_ide_release_dma\n", hwif->name); /* * Check if we have a valid dma handle. */ if (hwif->hw.dma != 0) { /* * Pause the DMA channel. */ ep93xx_dma_pause(hwif->hw.dma, 1, 0); /* * Flush the DMA channel */ ep93xx_dma_flush(hwif->hw.dma); }}/***************************************************************************** * * ep93xx_ide_callback() * * Registered with the ep93xx dma driver and called at the end of the dma * interrupt handler, this function should process the dma buffers. * ****************************************************************************/static voidep93xx_ide_callback(ep93xx_dma_int_t dma_int, ep93xx_dma_dev_t device, unsigned int user_data){ ide_drive_t *drive = (ide_drive_t *)user_data; ide_hwif_t *hwif = HWIF(drive); unsigned int temp; DPRINTK("ep93xx_ide_callback %d\n", dma_int); /* * Retrieve from the dma interface as many used buffers as are * available. */ while (ep93xx_dma_remove_buffer(hwif->hw.dma, &temp) == 0) g_prd_returned++; /* * Add new buffers if we have any available. */ while (g_prd_count) { /* * Check if this is a read or write operation. */ if (hwif->sg_dma_direction == PCI_DMA_FROMDEVICE) /* * Set up buffers for a read op. */ temp = ep93xx_dma_add_buffer(hwif->hw.dma, hwif->dma_base, hwif->dmatable_cpu[0], hwif->dmatable_cpu[1], 0, g_prd_count); else /* * Set up buffers for a write op. */ temp = ep93xx_dma_add_buffer(hwif->hw.dma, hwif->dmatable_cpu[0], hwif->dma_base, hwif->dmatable_cpu[1], 0, g_prd_count); /* * Add a buffer to the dma interface. */ if (temp != 0) break; hwif->dmatable_cpu += 2; /* * Decrement the count of dmatable entries */ g_prd_count--; } /* * See if all of the buffers have been returned. */ if (g_prd_returned >= g_prd_total) { /* * See if the IDE device is still requesting data. */ if (inl(IDECR) & IDECtrl_DMARQ) { /* * Indicate that an error has occurred during this * transfer. */ g_bad = 1; /* * Add another word to the DMA to try and satisfy the * device's request. */ if (hwif->sg_dma_direction == PCI_DMA_FROMDEVICE) ep93xx_dma_add_buffer(hwif->hw.dma, hwif->dma_base, virt_to_bus(&g_garbage), 4, 0, 0); else ep93xx_dma_add_buffer(hwif->hw.dma, virt_to_bus(&g_garbage), hwif->dma_base, 4, 0, 0); } }}/***************************************************************************** * * ep93xx_dma_timer_expiry() * * * dma_timer_expiry - handle a DMA timeout * @drive: Drive that timed out * * An IDE DMA transfer timed out. In the event of an error we ask * the driver to resolve the problem, if a DMA transfer is still * in progress we continue to wait (arguably we need to add a * secondary 'I dont care what the drive thinks' timeout here) * Finally if we have an interrupt we let it complete the I/O. * But only one time - we clear expiry and if it's still not * completed after WAIT_CMD, we error and retry in PIO. * This can occur if an interrupt is lost or due to hang or bugs. * * ****************************************************************************/static intep93xx_idedma_timer_expiry(ide_drive_t *drive){ ide_hwif_t *hwif = HWIF(drive); u8 dev_stat = hwif->INB(IDE_ALTSTATUS_REG); u8 irq_stat = inl(IDECR) & IDECtrl_INTRQ; DPRINTK(KERN_WARNING "%s: dma_timer_expiry: dev status == 0x%02x,irq= %d\n", drive->name, dev_stat, irq_stat); /* * Clear the expiry handler in case we decide to wait more, * next time timer expires it is an error */ HWGROUP(drive)->expiry = NULL; /* * If the interrupt is asserted, call the handler. */ if (irq_stat) HWGROUP(drive)->handler(drive); /* * Check if the busy bit or the drq bit is set, indicating that * a dma transfer is still active, or the IDE interrupt is asserted. */ if ( (dev_stat & 0x80) || (dev_stat & 0x08) || irq_stat) return WAIT_CMD; /* * the device is not busy and the interrupt is not asserted, so check * if there's an error. */ if (dev_stat & 0x01) /* ERROR */ return -1; return 0; /* Unknown status -- reset the bus */}/***************************************************************************** * * ep93xx_config_ide_device() * * This function sets up the ep93xx ide device for a dma transfer by first * probing to find the best dma mode supported by the device. * * Returns a 0 for success, and a 1 otherwise. * ****************************************************************************/static unsigned intep93xx_config_ide_device(ide_drive_t *drive){ byte transfer = 0; DPRINTK("%s: ep93xx_config_ide_device\n", drive->name); /* * Determine the best transfer speed supported. */ transfer = ide_dma_speed(drive, 2); /* * Do not use MW DMA modes above 0 on ATAPI devices since they excite a * chip bug. */ if ((drive->media != ide_disk) && ((transfer == XFER_MW_DMA_2) || (transfer == XFER_MW_DMA_1))) transfer = XFER_MW_DMA_0; /* * Do nothing if a DMA mode is not supported. */ if (transfer == 0) return HWIF(drive)->ide_dma_off(drive); /* * Configure the drive. */ if (ide_config_drive_speed(drive, transfer) == 0) { /* * Hold on to this value for use later. */ drive->current_speed = transfer; /* * Success, so turn on DMA. */ return HWIF(drive)->ide_dma_on(drive); } else return HWIF(drive)->ide_dma_off(drive);}/***************************************************************************** * * ep93xx_set_pio() * * Configures the ep93xx controller for a PIO mode transfer. * ****************************************************************************/static voidep93xx_set_pio(void){ DPRINTK("ep93xx_set_pio\n"); /* * Clear the MDMA and UDMA operation registers. */ outl(0, IDEMDMAOP); outl(0, IDEUDMAOP); /* * Reset the UDMA state machine. */ outl(IDEUDMADebug_RWOE | IDEUDMADebug_RWPTR | IDEUDMADebug_RWDR | IDEUDMADebug_RROE | IDEUDMADebug_RRPTR | IDEUDMADebug_RRDR, IDEUDMADEBUG); outl(0, IDEUDMADEBUG); /* * Enable PIO mode of operation. */ outl(IDECfg_PIO | IDECfg_IDEEN | (4 << IDECfg_MODE_SHIFT) | (1 << IDECfg_WST_SHIFT), IDECFG);}/***************************************************************************** * * ep93xx_rwproc() * * Initializes the ep93xx IDE controller interface with the transfer type, * transfer mode, and transfer direction. * ****************************************************************************/static voidep93xx_rwproc(ide_drive_t *drive, int action){ DPRINTK("%s: ep93xx_rwproc\n", drive->name); /* * Configure the IDE controller for the specified transfer mode. */ switch (drive->current_speed) { /* * Configure for an MDMA operation. */ case XFER_MW_DMA_0: case XFER_MW_DMA_1: case XFER_MW_DMA_2: outl(((drive->current_speed & 3) << IDECfg_MODE_SHIFT) | IDECfg_MDMA | IDECfg_IDEEN, IDECFG); outl(action ? IDEMDMAOp_RWOP : 0, IDEMDMAOP); outl(inl(IDEMDMAOP) | IDEMDMAOp_MEN, IDEMDMAOP); break; /* * Configure for a UDMA operation. */ case XFER_UDMA_0: case XFER_UDMA_1: case XFER_UDMA_2: case XFER_UDMA_3: case XFER_UDMA_4: outl(((drive->current_speed & 7) << IDECfg_MODE_SHIFT) | IDECfg_UDMA | IDECfg_IDEEN, IDECFG); outl(action ? IDEUDMAOp_RWOP : 0, IDEUDMAOP); outl(inl(IDEUDMAOP) | IDEUDMAOp_UEN, IDEUDMAOP); break; default: break; }}/***************************************************************************** * * ep93xx_ide_dma_check() * * This function determines if the device supports dma transfers, and if it * does, then enables dma. * ****************************************************************************/static intep93xx_ide_dma_check(ide_drive_t *drive){ ide_hwif_t * hwif = HWIF(drive); struct hd_driveid *id = drive->id; DPRINTK("%s: ep93xx_ide_dma_check\n", drive->name); if (!id || !(id->capability & 1) || !hwif->autodma) { /* * Disable dma for this drive. */ hwif->ide_dma_off_quietly(drive); return 1; } /* * Consult the list of known "bad" drives */ if (in_drive_list(id, drive_blacklist)) { printk("%s: Disabling DMA for %s (blacklisted)\n", drive->name, id->model); /* * Disable dma for this drive. */ hwif->ide_dma_off_quietly(drive); return 1; } /* * Check if the drive supports multiword dma or udma modes. * If it does, then set the device up for that * type of dma transfer, and call ep93xx_ide_dma_on. */ return ep93xx_config_ide_device(drive);}/***************************************************************************** * * ep93xx_ide_dma_host_off() * * This function disables dma for the host. * ****************************************************************************/static intep93xx_ide_dma_host_off(ide_drive_t *drive){ ide_hwif_t *hwif = HWIF(drive); /* * TODO: what's to be done here? */ DPRINTK("%s: ep93xx_ide_dma_host_off\n", drive->name); /* * Release the dma channel and all memory allocated for dma * purposes. */ ep93xx_ide_release_dma(hwif); /* * Success. */ return 0;}/***************************************************************************** * * ep93xx_ide_dma_off_quietly() * * This function, without announcing it, disables dma for the device. * ****************************************************************************/static intep93xx_ide_dma_off_quietly(ide_drive_t *drive){ DPRINTK("%s: ep93xx_ide_dma_off_quietly\n", drive->name); /* * Clear the using_dma field to indicate that dma is disabled * for this drive. */ drive->using_dma = 0; /* * Disable dma on the host side. */ return HWIF(drive)->ide_dma_host_off(drive);}/***************************************************************************** * * ep93xx_ide_dma_off() * * This function disables dma for the device. * ****************************************************************************/static intep93xx_ide_dma_off(ide_drive_t *drive){ DPRINTK("%s: ep93xx_ide_dma_off\n", drive->name); return HWIF(drive)->ide_dma_off_quietly(drive);}/***************************************************************************** * * ep93xx_ide_dma_on() * * This function enables dma for the device. * ****************************************************************************/static intep93xx_ide_dma_on(ide_drive_t *drive){ DPRINTK("%s: ep93xx_ide_dma_on\n", drive->name); /* * Set the using_dma field to indicate that dma is enabled. */ drive->using_dma = 1; /* * Enable DMA on the host side. */ return HWIF(drive)->ide_dma_host_on(drive);}/***************************************************************************** * * ep93xx_ide_dma_host_on() * * This function enables dma for the device. * ****************************************************************************/static intep93xx_ide_dma_host_on(ide_drive_t *drive){ DPRINTK("%s: ep93xx_ide_dma_host_on\n", drive->name); if (drive->using_dma)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -