📄 ide-ep93xx.c
字号:
return 0; return 1;}/***************************************************************************** * * ep93xx_ide_dma_read() * * This function sets up a dma read operation. * ****************************************************************************/static intep93xx_ide_dma_read(ide_drive_t *drive){ u8 lba48 = (drive->addressing == 1) ? 1 : 0; struct request *rq = HWGROUP(drive)->rq; unsigned int flags, i; ide_hwif_t *hwif = HWIF(drive); task_ioreg_t command = WIN_NOP; DPRINTK("%s: ep93xx_ide_dma_read\n", drive->name); DPRINTK(" %ld, %ld\n", HWGROUP(drive)->rq->sector, HWGROUP(drive)->rq->nr_sectors); /* * Check if we are already transferring on this dma channel. */ if (hwif->sg_dma_active || drive->waiting_for_dma) { DPRINTK("%s: dma_read: dma already active \n", drive->name); return 1; } /* * Compute the array index used for this request. */ i = drive->name[2] == 'a' ? 0 : 2; /* * See if this request matches the most recent request, and that the * most recent request ended in error. */ if (g_bad && (g_cmd == READ) && (g_drive == drive) && (g_sector == HWGROUP(drive)->rq->sector) && (g_nr_sectors == HWGROUP(drive)->rq->nr_sectors)) { g_cur_retries++; if (g_cur_retries > g_max_retries[i]) g_max_retries[i]++; if (g_cur_retries == RETRIES_PER_TRANSFER) { g_bad = 0; return 1; } } else { g_cur_retries = 0; g_cmd = READ; g_drive = drive; g_sector = HWGROUP(drive)->rq->sector; g_nr_sectors = HWGROUP(drive)->rq->nr_sectors; } /* * Save information about this transfer. */ g_xfers[i]++; g_sectors[i] += HWGROUP(drive)->rq->nr_sectors; /* * Indicate that we're waiting for dma. */ drive->waiting_for_dma = 1; /* * Configure DMA M2M channel flags for a source address hold, h/w * initiated P2M transfer. */ flags = (SOURCE_HOLD | TRANSFER_MODE_HW_P2M); if (drive->current_speed & 0x20) { flags |= (WS_IDE_MDMA_READ << WAIT_STATES_SHIFT); /* * MDMA data register address. */ hwif->dma_base = IDEMDMADATAIN - IO_BASE_VIRT + IO_BASE_PHYS; } else { flags |= (WS_IDE_UDMA_READ << WAIT_STATES_SHIFT); /* * UDMA data register address. */ hwif->dma_base = IDEUDMADATAIN - IO_BASE_VIRT + IO_BASE_PHYS; } /* * Configure the dma interface for this IDE operation. */ if (ep93xx_dma_config(hwif->hw.dma, 0, flags, ep93xx_ide_callback, (unsigned int)drive) != 0) { DPRINTK("%s: ep93xx_ide_dma_read: ERROR- dma config failed", drive->name); drive->waiting_for_dma = 0; /* * Fail. */ return 1; } /* * Build the table of dma-able buffers. */ if (!(g_prd_count = ide_build_dmatable(drive))) { DPRINTK("%s: ep93xx_ide_dma_read: ERROR- failed to build dma table", drive->name); drive->waiting_for_dma = 0; /* * Fail, try PIO instead of DMA */ return 1; } /* * Indicate that the scatter gather is active. */ hwif->sg_dma_active = 1; /* * test stuff */ g_prd_total = g_prd_count; g_prd_returned = 0; DPRINTK("%d buffers\n", g_prd_total); /* * Prepare the dma interface with some buffers from the * dma_table. */ do { /* * Add a buffer to the dma interface. */ if (ep93xx_dma_add_buffer(hwif->hw.dma, hwif->dma_base, hwif->dmatable_cpu[0], hwif->dmatable_cpu[1], 0, g_prd_count) != 0) break; hwif->dmatable_cpu += 2; /* * Decrement the count of dmatable entries */ g_prd_count--; } while (g_prd_count); /* * Nothing further is required if this is not a ide_disk (i.e. an ATAPI * device). */ if (drive->media != ide_disk) return 0; /* * Determine the command to be sent to the device. */ command = (lba48) ? WIN_READDMA_EXT : WIN_READDMA; if (rq->cmd == IDE_DRIVE_TASKFILE) { ide_task_t *args = rq->special; command = args->tfRegister[IDE_COMMAND_OFFSET]; } /* * Send the read command to the device. */ ide_execute_command(drive, command, &ep93xx_ide_dma_intr, 2*WAIT_CMD, &ep93xx_idedma_timer_expiry); /* * initiate the dma transfer. */ return hwif->ide_dma_begin(drive);}/***************************************************************************** * * ep93xx_ide_dma_first_read() * * This function handles the very first dma read operation. * ****************************************************************************/static intep93xx_ide_dma_first_read(ide_drive_t *drive){ ide_hwif_t *hwif = HWIF(drive); /* * Switch the hwif to the real read routine. */ hwif->ide_dma_read = ep93xx_ide_dma_read; /* * Register a proc entry for the statistics that we gather. */#ifdef CONFIG_PROC_FS create_proc_info_entry("ide/ep93xx", 0, 0, ep93xx_get_info);#endif /* * Do the actual read. */ return hwif->ide_dma_read(drive);}/***************************************************************************** * * ep93xx_ide_dma_write() * * This function sets up a dma write operation. * ****************************************************************************/static intep93xx_ide_dma_write(ide_drive_t *drive){ u8 lba48 = (drive->addressing == 1) ? 1 : 0; struct request *rq = HWGROUP(drive)->rq; unsigned int flags, i; ide_hwif_t *hwif = HWIF(drive); task_ioreg_t command = WIN_NOP; DPRINTK("%s: ep93xx_ide_dma_write\n", drive->name); /* * Check if we are already transferring on this dma channel. */ if (hwif->sg_dma_active || drive->waiting_for_dma) { DPRINTK("%s: dma_write - dma is already active \n", drive->name); return 1; } /* * Compute the array index used for this request. */ i = drive->name[2] == 'a' ? 1 : 3; /* * See if this request matches the most recent request, and that the * most recent request ended in error. */ if (g_bad && (g_cmd == WRITE) && (g_drive == drive) && (g_sector == HWGROUP(drive)->rq->sector) && (g_nr_sectors == HWGROUP(drive)->rq->nr_sectors)) { g_cur_retries++; if (g_cur_retries > g_max_retries[i]) g_max_retries[i]++; if (g_cur_retries == RETRIES_PER_TRANSFER) { g_bad = 0; return 1; } } else { g_cur_retries = 0; g_cmd = WRITE; g_drive = drive; g_sector = HWGROUP(drive)->rq->sector; g_nr_sectors = HWGROUP(drive)->rq->nr_sectors; } /* * Save information about this transfer. */ g_xfers[i]++; g_sectors[i] += HWGROUP(drive)->rq->nr_sectors; /* * Indicate that we're waiting for dma. */ drive->waiting_for_dma = 1; /* * Configure DMA M2M channel flags for a destination address * hold, h/w initiated M2P transfer. */ flags = (DESTINATION_HOLD | TRANSFER_MODE_HW_M2P); /* * Determine if we need the MDMA or UDMA data register. */ if (drive->current_speed & 0x20) { flags |= (WS_IDE_MDMA_WRITE << WAIT_STATES_SHIFT); /* * MDMA data register address. */ hwif->dma_base = IDEMDMADATAOUT - IO_BASE_VIRT + IO_BASE_PHYS; } else { flags |= (WS_IDE_UDMA_WRITE << WAIT_STATES_SHIFT); /* * UDMA data register address. */ hwif->dma_base = IDEUDMADATAOUT - IO_BASE_VIRT + IO_BASE_PHYS; } /* * Configure the dma interface for this IDE operation. */ if (ep93xx_dma_config(hwif->hw.dma, 0, flags, ep93xx_ide_callback, (unsigned int)drive) != 0) { drive->waiting_for_dma = 0; return 1; } /* * Build the table of dma-able buffers. */ if (!(g_prd_count = ide_build_dmatable(drive))) { drive->waiting_for_dma = 0; /* * Fail, try PIO instead of DMA */ return 1; } /* * Indicate that we're waiting for dma. */ hwif->sg_dma_active = 1; /* * test stuff */ g_prd_total = g_prd_count; g_prd_returned = 0; /* * Prepare the dma interface with some buffers from the * dma_table. */ do { /* * Add a buffer to the dma interface. */ if (ep93xx_dma_add_buffer(hwif->hw.dma, hwif->dmatable_cpu[0], hwif->dma_base, hwif->dmatable_cpu[1], 0, g_prd_count) != 0) break; hwif->dmatable_cpu += 2; /* * Decrement the count of dmatable entries */ g_prd_count--; } while (g_prd_count); /* * Nothing further is required if this is not a ide_disk (i.e. an ATAPI * device). */ if (drive->media != ide_disk) return 0; /* * Determine the command to be sent to the device. */ command = (lba48) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA; if (rq->cmd == IDE_DRIVE_TASKFILE) { ide_task_t *args = rq->special; command = args->tfRegister[IDE_COMMAND_OFFSET]; } /* * Send the write dma command to the device. */ ide_execute_command(drive, command, &ep93xx_ide_dma_intr, 2*WAIT_CMD, &ep93xx_idedma_timer_expiry); /* * initiate the dma transfer. */ return hwif->ide_dma_begin(drive);}/***************************************************************************** * * ep93xx_ide_dma_begin() * * This function initiates a dma transfer. * ****************************************************************************/static intep93xx_ide_dma_begin(ide_drive_t *drive){ ide_hwif_t *hwif = HWIF(drive); DPRINTK("%s: ep93xx_ide_dma_begin\n", drive->name); /* * The transfer is not bad yet. */ g_bad = 0; /* * Configure the ep93xx ide controller for a dma operation. */ if (HWGROUP(drive)->rq->cmd == READ) ep93xx_rwproc(drive, 0); else ep93xx_rwproc(drive, 1); /* * Start the dma transfer. */ ep93xx_dma_start(hwif->hw.dma, 1, NULL); return 0;}/***************************************************************************** * * ep93xx_ide_dma_end() * * This function performs any tasks needed to cleanup after a dma transfer. * Returns 1 if an error occured, and 0 otherwise. * ****************************************************************************/static intep93xx_ide_dma_end(ide_drive_t *drive){ ide_hwif_t * hwif = HWIF(drive); int i, stat; DPRINTK("%s: ep93xx_ide_dma_end\n", drive->name); /* * See if there is any data left in UDMA FIFOs. For a read, first wait * until either the DMA is done or the FIFO is empty. If there is any * residual data in the FIFO, there was an error in the transfer. */ if (HWGROUP(drive)->rq->cmd == READ) { do { i = inl(IDEUDMARFST); } while (!ep93xx_dma_is_done(hwif->hw.dma) && ((i & 15) != ((i >> 4) & 15))); udelay(1); } else i = inl(IDEUDMAWFST); if ((i & 15) != ((i >> 4) & 15)) g_bad = 1; /* * See if all of the buffers were returned by the DMA driver. If not, * then a transfer error has occurred. */ if (!ep93xx_dma_is_done(hwif->hw.dma)) g_bad = 1; /* * Put the dma interface into pause mode. */ ep93xx_dma_pause(hwif->hw.dma, 1, 0); ep93xx_dma_flush(hwif->hw.dma); /* * Enable PIO mode on the IDE interface. */ ep93xx_set_pio(); /* * Indicate there's no dma transfer currently in progress. */ hwif->sg_dma_active = 0; drive->waiting_for_dma = 0; /* * Get status from the ide device. */ stat = HWIF(drive)->INB(IDE_STATUS_REG); /* * If this is an ATAPI device and it reported an error, then simply * return a DMA success. */ if ((drive->media != ide_disk) && (stat & ERR_STAT)) return 0; /* * See if a CRC error occurred. If so, then a transfer error has * occurred. */ if ((stat & ERR_STAT) && (HWIF(drive)->INB(IDE_ERROR_REG) & ICRC_ERR)) g_bad = 1; /* * Compute the array index used for this request. */ i = HWGROUP(drive)->rq->cmd == READ ? 0 : 1; i += drive->name[2] == 'a' ? 0 : 2; /* * Fail if an error occurred during the DMA. */ if (g_bad) { /* * Increment the number of retries for this request, along with * the number of consecutive errors for this drive. */ g_retries[i]++; g_errors[i]++; /* * See if the maximum number of consective errors has occurred.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -