18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * IDE DMA support (including IDE PCI BM-DMA). 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 1995-1998 Mark Lord 58c2ecf20Sopenharmony_ci * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org> 68c2ecf20Sopenharmony_ci * Copyright (C) 2004, 2007 Bartlomiej Zolnierkiewicz 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * May be copied or modified under the terms of the GNU General Public License 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * DMA is supported for all IDE devices (disk drives, cdroms, tapes, floppies). 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci/* 148c2ecf20Sopenharmony_ci * Special Thanks to Mark for his Six years of work. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* 188c2ecf20Sopenharmony_ci * Thanks to "Christopher J. Reimer" <reimer@doe.carleton.ca> for 198c2ecf20Sopenharmony_ci * fixing the problem with the BIOS on some Acer motherboards. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * Thanks to "Benoit Poulot-Cazajous" <poulot@chorus.fr> for testing 228c2ecf20Sopenharmony_ci * "TX" chipset compatibility and for providing patches for the "TX" chipset. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * Thanks to Christian Brunner <chb@muc.de> for taking a good first crack 258c2ecf20Sopenharmony_ci * at generic DMA -- his patches were referred to when preparing this code. 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * Most importantly, thanks to Robert Bringman <rob@mars.trion.com> 288c2ecf20Sopenharmony_ci * for supplying a Promise UDMA board & WD UDMA drive for this work! 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <linux/types.h> 328c2ecf20Sopenharmony_ci#include <linux/gfp.h> 338c2ecf20Sopenharmony_ci#include <linux/kernel.h> 348c2ecf20Sopenharmony_ci#include <linux/export.h> 358c2ecf20Sopenharmony_ci#include <linux/ide.h> 368c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 378c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic const struct drive_list_entry drive_whitelist[] = { 408c2ecf20Sopenharmony_ci { "Micropolis 2112A" , NULL }, 418c2ecf20Sopenharmony_ci { "CONNER CTMA 4000" , NULL }, 428c2ecf20Sopenharmony_ci { "CONNER CTT8000-A" , NULL }, 438c2ecf20Sopenharmony_ci { "ST34342A" , NULL }, 448c2ecf20Sopenharmony_ci { NULL , NULL } 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic const struct drive_list_entry drive_blacklist[] = { 488c2ecf20Sopenharmony_ci { "WDC AC11000H" , NULL }, 498c2ecf20Sopenharmony_ci { "WDC AC22100H" , NULL }, 508c2ecf20Sopenharmony_ci { "WDC AC32500H" , NULL }, 518c2ecf20Sopenharmony_ci { "WDC AC33100H" , NULL }, 528c2ecf20Sopenharmony_ci { "WDC AC31600H" , NULL }, 538c2ecf20Sopenharmony_ci { "WDC AC32100H" , "24.09P07" }, 548c2ecf20Sopenharmony_ci { "WDC AC23200L" , "21.10N21" }, 558c2ecf20Sopenharmony_ci { "Compaq CRD-8241B" , NULL }, 568c2ecf20Sopenharmony_ci { "CRD-8400B" , NULL }, 578c2ecf20Sopenharmony_ci { "CRD-8480B", NULL }, 588c2ecf20Sopenharmony_ci { "CRD-8482B", NULL }, 598c2ecf20Sopenharmony_ci { "CRD-84" , NULL }, 608c2ecf20Sopenharmony_ci { "SanDisk SDP3B" , NULL }, 618c2ecf20Sopenharmony_ci { "SanDisk SDP3B-64" , NULL }, 628c2ecf20Sopenharmony_ci { "SANYO CD-ROM CRD" , NULL }, 638c2ecf20Sopenharmony_ci { "HITACHI CDR-8" , NULL }, 648c2ecf20Sopenharmony_ci { "HITACHI CDR-8335" , NULL }, 658c2ecf20Sopenharmony_ci { "HITACHI CDR-8435" , NULL }, 668c2ecf20Sopenharmony_ci { "Toshiba CD-ROM XM-6202B" , NULL }, 678c2ecf20Sopenharmony_ci { "TOSHIBA CD-ROM XM-1702BC", NULL }, 688c2ecf20Sopenharmony_ci { "CD-532E-A" , NULL }, 698c2ecf20Sopenharmony_ci { "E-IDE CD-ROM CR-840", NULL }, 708c2ecf20Sopenharmony_ci { "CD-ROM Drive/F5A", NULL }, 718c2ecf20Sopenharmony_ci { "WPI CDD-820", NULL }, 728c2ecf20Sopenharmony_ci { "SAMSUNG CD-ROM SC-148C", NULL }, 738c2ecf20Sopenharmony_ci { "SAMSUNG CD-ROM SC", NULL }, 748c2ecf20Sopenharmony_ci { "ATAPI CD-ROM DRIVE 40X MAXIMUM", NULL }, 758c2ecf20Sopenharmony_ci { "_NEC DV5800A", NULL }, 768c2ecf20Sopenharmony_ci { "SAMSUNG CD-ROM SN-124", "N001" }, 778c2ecf20Sopenharmony_ci { "Seagate STT20000A", NULL }, 788c2ecf20Sopenharmony_ci { "CD-ROM CDR_U200", "1.09" }, 798c2ecf20Sopenharmony_ci { NULL , NULL } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci}; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/** 848c2ecf20Sopenharmony_ci * ide_dma_intr - IDE DMA interrupt handler 858c2ecf20Sopenharmony_ci * @drive: the drive the interrupt is for 868c2ecf20Sopenharmony_ci * 878c2ecf20Sopenharmony_ci * Handle an interrupt completing a read/write DMA transfer on an 888c2ecf20Sopenharmony_ci * IDE device 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ciide_startstop_t ide_dma_intr(ide_drive_t *drive) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 948c2ecf20Sopenharmony_ci struct ide_cmd *cmd = &hwif->cmd; 958c2ecf20Sopenharmony_ci u8 stat = 0, dma_stat = 0; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci drive->waiting_for_dma = 0; 988c2ecf20Sopenharmony_ci dma_stat = hwif->dma_ops->dma_end(drive); 998c2ecf20Sopenharmony_ci ide_dma_unmap_sg(drive, cmd); 1008c2ecf20Sopenharmony_ci stat = hwif->tp_ops->read_status(hwif); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (OK_STAT(stat, DRIVE_READY, drive->bad_wstat | ATA_DRQ)) { 1038c2ecf20Sopenharmony_ci if (!dma_stat) { 1048c2ecf20Sopenharmony_ci if ((cmd->tf_flags & IDE_TFLAG_FS) == 0) 1058c2ecf20Sopenharmony_ci ide_finish_cmd(drive, cmd, stat); 1068c2ecf20Sopenharmony_ci else 1078c2ecf20Sopenharmony_ci ide_complete_rq(drive, BLK_STS_OK, 1088c2ecf20Sopenharmony_ci blk_rq_sectors(cmd->rq) << 9); 1098c2ecf20Sopenharmony_ci return ide_stopped; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: %s: bad DMA status (0x%02x)\n", 1128c2ecf20Sopenharmony_ci drive->name, __func__, dma_stat); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci return ide_error(drive, "dma_intr", stat); 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ciint ide_dma_good_drive(ide_drive_t *drive) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci return ide_in_drive_list(drive->id, drive_whitelist); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/** 1238c2ecf20Sopenharmony_ci * ide_dma_map_sg - map IDE scatter gather for DMA I/O 1248c2ecf20Sopenharmony_ci * @drive: the drive to map the DMA table for 1258c2ecf20Sopenharmony_ci * @cmd: command 1268c2ecf20Sopenharmony_ci * 1278c2ecf20Sopenharmony_ci * Perform the DMA mapping magic necessary to access the source or 1288c2ecf20Sopenharmony_ci * target buffers of a request via DMA. The lower layers of the 1298c2ecf20Sopenharmony_ci * kernel provide the necessary cache management so that we can 1308c2ecf20Sopenharmony_ci * operate in a portable fashion. 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic int ide_dma_map_sg(ide_drive_t *drive, struct ide_cmd *cmd) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 1368c2ecf20Sopenharmony_ci struct scatterlist *sg = hwif->sg_table; 1378c2ecf20Sopenharmony_ci int i; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (cmd->tf_flags & IDE_TFLAG_WRITE) 1408c2ecf20Sopenharmony_ci cmd->sg_dma_direction = DMA_TO_DEVICE; 1418c2ecf20Sopenharmony_ci else 1428c2ecf20Sopenharmony_ci cmd->sg_dma_direction = DMA_FROM_DEVICE; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci i = dma_map_sg(hwif->dev, sg, cmd->sg_nents, cmd->sg_dma_direction); 1458c2ecf20Sopenharmony_ci if (i) { 1468c2ecf20Sopenharmony_ci cmd->orig_sg_nents = cmd->sg_nents; 1478c2ecf20Sopenharmony_ci cmd->sg_nents = i; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci return i; 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci/** 1548c2ecf20Sopenharmony_ci * ide_dma_unmap_sg - clean up DMA mapping 1558c2ecf20Sopenharmony_ci * @drive: The drive to unmap 1568c2ecf20Sopenharmony_ci * 1578c2ecf20Sopenharmony_ci * Teardown mappings after DMA has completed. This must be called 1588c2ecf20Sopenharmony_ci * after the completion of each use of ide_build_dmatable and before 1598c2ecf20Sopenharmony_ci * the next use of ide_build_dmatable. Failure to do so will cause 1608c2ecf20Sopenharmony_ci * an oops as only one mapping can be live for each target at a given 1618c2ecf20Sopenharmony_ci * time. 1628c2ecf20Sopenharmony_ci */ 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_civoid ide_dma_unmap_sg(ide_drive_t *drive, struct ide_cmd *cmd) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci dma_unmap_sg(hwif->dev, hwif->sg_table, cmd->orig_sg_nents, 1698c2ecf20Sopenharmony_ci cmd->sg_dma_direction); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_dma_unmap_sg); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/** 1748c2ecf20Sopenharmony_ci * ide_dma_off_quietly - Generic DMA kill 1758c2ecf20Sopenharmony_ci * @drive: drive to control 1768c2ecf20Sopenharmony_ci * 1778c2ecf20Sopenharmony_ci * Turn off the current DMA on this IDE controller. 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_civoid ide_dma_off_quietly(ide_drive_t *drive) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci drive->dev_flags &= ~IDE_DFLAG_USING_DMA; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci drive->hwif->dma_ops->dma_host_set(drive, 0); 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ide_dma_off_quietly); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci/** 1898c2ecf20Sopenharmony_ci * ide_dma_off - disable DMA on a device 1908c2ecf20Sopenharmony_ci * @drive: drive to disable DMA on 1918c2ecf20Sopenharmony_ci * 1928c2ecf20Sopenharmony_ci * Disable IDE DMA for a device on this IDE controller. 1938c2ecf20Sopenharmony_ci * Inform the user that DMA has been disabled. 1948c2ecf20Sopenharmony_ci */ 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_civoid ide_dma_off(ide_drive_t *drive) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: DMA disabled\n", drive->name); 1998c2ecf20Sopenharmony_ci ide_dma_off_quietly(drive); 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ide_dma_off); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci/** 2048c2ecf20Sopenharmony_ci * ide_dma_on - Enable DMA on a device 2058c2ecf20Sopenharmony_ci * @drive: drive to enable DMA on 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci * Enable IDE DMA for a device on this IDE controller. 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_civoid ide_dma_on(ide_drive_t *drive) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci drive->dev_flags |= IDE_DFLAG_USING_DMA; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci drive->hwif->dma_ops->dma_host_set(drive, 1); 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ciint __ide_dma_bad_drive(ide_drive_t *drive) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci u16 *id = drive->id; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci int blacklist = ide_in_drive_list(id, drive_blacklist); 2228c2ecf20Sopenharmony_ci if (blacklist) { 2238c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: Disabling (U)DMA for %s (blacklisted)\n", 2248c2ecf20Sopenharmony_ci drive->name, (char *)&id[ATA_ID_PROD]); 2258c2ecf20Sopenharmony_ci return blacklist; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci return 0; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__ide_dma_bad_drive); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic const u8 xfer_mode_bases[] = { 2328c2ecf20Sopenharmony_ci XFER_UDMA_0, 2338c2ecf20Sopenharmony_ci XFER_MW_DMA_0, 2348c2ecf20Sopenharmony_ci XFER_SW_DMA_0, 2358c2ecf20Sopenharmony_ci}; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci u16 *id = drive->id; 2408c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 2418c2ecf20Sopenharmony_ci const struct ide_port_ops *port_ops = hwif->port_ops; 2428c2ecf20Sopenharmony_ci unsigned int mask = 0; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci switch (base) { 2458c2ecf20Sopenharmony_ci case XFER_UDMA_0: 2468c2ecf20Sopenharmony_ci if ((id[ATA_ID_FIELD_VALID] & 4) == 0) 2478c2ecf20Sopenharmony_ci break; 2488c2ecf20Sopenharmony_ci mask = id[ATA_ID_UDMA_MODES]; 2498c2ecf20Sopenharmony_ci if (port_ops && port_ops->udma_filter) 2508c2ecf20Sopenharmony_ci mask &= port_ops->udma_filter(drive); 2518c2ecf20Sopenharmony_ci else 2528c2ecf20Sopenharmony_ci mask &= hwif->ultra_mask; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci /* 2558c2ecf20Sopenharmony_ci * avoid false cable warning from eighty_ninty_three() 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_ci if (req_mode > XFER_UDMA_2) { 2588c2ecf20Sopenharmony_ci if ((mask & 0x78) && (eighty_ninty_three(drive) == 0)) 2598c2ecf20Sopenharmony_ci mask &= 0x07; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci break; 2628c2ecf20Sopenharmony_ci case XFER_MW_DMA_0: 2638c2ecf20Sopenharmony_ci mask = id[ATA_ID_MWDMA_MODES]; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci /* Also look for the CF specific MWDMA modes... */ 2668c2ecf20Sopenharmony_ci if (ata_id_is_cfa(id) && (id[ATA_ID_CFA_MODES] & 0x38)) { 2678c2ecf20Sopenharmony_ci u8 mode = ((id[ATA_ID_CFA_MODES] & 0x38) >> 3) - 1; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci mask |= ((2 << mode) - 1) << 3; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (port_ops && port_ops->mdma_filter) 2738c2ecf20Sopenharmony_ci mask &= port_ops->mdma_filter(drive); 2748c2ecf20Sopenharmony_ci else 2758c2ecf20Sopenharmony_ci mask &= hwif->mwdma_mask; 2768c2ecf20Sopenharmony_ci break; 2778c2ecf20Sopenharmony_ci case XFER_SW_DMA_0: 2788c2ecf20Sopenharmony_ci mask = id[ATA_ID_SWDMA_MODES]; 2798c2ecf20Sopenharmony_ci if (!(mask & ATA_SWDMA2) && (id[ATA_ID_OLD_DMA_MODES] >> 8)) { 2808c2ecf20Sopenharmony_ci u8 mode = id[ATA_ID_OLD_DMA_MODES] >> 8; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci /* 2838c2ecf20Sopenharmony_ci * if the mode is valid convert it to the mask 2848c2ecf20Sopenharmony_ci * (the maximum allowed mode is XFER_SW_DMA_2) 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_ci if (mode <= 2) 2878c2ecf20Sopenharmony_ci mask = (2 << mode) - 1; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci mask &= hwif->swdma_mask; 2908c2ecf20Sopenharmony_ci break; 2918c2ecf20Sopenharmony_ci default: 2928c2ecf20Sopenharmony_ci BUG(); 2938c2ecf20Sopenharmony_ci break; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return mask; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci/** 3008c2ecf20Sopenharmony_ci * ide_find_dma_mode - compute DMA speed 3018c2ecf20Sopenharmony_ci * @drive: IDE device 3028c2ecf20Sopenharmony_ci * @req_mode: requested mode 3038c2ecf20Sopenharmony_ci * 3048c2ecf20Sopenharmony_ci * Checks the drive/host capabilities and finds the speed to use for 3058c2ecf20Sopenharmony_ci * the DMA transfer. The speed is then limited by the requested mode. 3068c2ecf20Sopenharmony_ci * 3078c2ecf20Sopenharmony_ci * Returns 0 if the drive/host combination is incapable of DMA transfers 3088c2ecf20Sopenharmony_ci * or if the requested mode is not a DMA mode. 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ciu8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 3148c2ecf20Sopenharmony_ci unsigned int mask; 3158c2ecf20Sopenharmony_ci int x, i; 3168c2ecf20Sopenharmony_ci u8 mode = 0; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (drive->media != ide_disk) { 3198c2ecf20Sopenharmony_ci if (hwif->host_flags & IDE_HFLAG_NO_ATAPI_DMA) 3208c2ecf20Sopenharmony_ci return 0; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(xfer_mode_bases); i++) { 3248c2ecf20Sopenharmony_ci if (req_mode < xfer_mode_bases[i]) 3258c2ecf20Sopenharmony_ci continue; 3268c2ecf20Sopenharmony_ci mask = ide_get_mode_mask(drive, xfer_mode_bases[i], req_mode); 3278c2ecf20Sopenharmony_ci x = fls(mask) - 1; 3288c2ecf20Sopenharmony_ci if (x >= 0) { 3298c2ecf20Sopenharmony_ci mode = xfer_mode_bases[i] + x; 3308c2ecf20Sopenharmony_ci break; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (hwif->chipset == ide_acorn && mode == 0) { 3358c2ecf20Sopenharmony_ci /* 3368c2ecf20Sopenharmony_ci * is this correct? 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_ci if (ide_dma_good_drive(drive) && 3398c2ecf20Sopenharmony_ci drive->id[ATA_ID_EIDE_DMA_TIME] < 150) 3408c2ecf20Sopenharmony_ci mode = XFER_MW_DMA_1; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci mode = min(mode, req_mode); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: %s mode selected\n", drive->name, 3468c2ecf20Sopenharmony_ci mode ? ide_xfer_verbose(mode) : "no DMA"); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci return mode; 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic int ide_tune_dma(ide_drive_t *drive) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 3548c2ecf20Sopenharmony_ci u8 speed; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (ata_id_has_dma(drive->id) == 0 || 3578c2ecf20Sopenharmony_ci (drive->dev_flags & IDE_DFLAG_NODMA)) 3588c2ecf20Sopenharmony_ci return 0; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* consult the list of known "bad" drives */ 3618c2ecf20Sopenharmony_ci if (__ide_dma_bad_drive(drive)) 3628c2ecf20Sopenharmony_ci return 0; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA) 3658c2ecf20Sopenharmony_ci return config_drive_for_dma(drive); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci speed = ide_max_dma_mode(drive); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci if (!speed) 3708c2ecf20Sopenharmony_ci return 0; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (ide_set_dma_mode(drive, speed)) 3738c2ecf20Sopenharmony_ci return 0; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci return 1; 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic int ide_dma_check(ide_drive_t *drive) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if (ide_tune_dma(drive)) 3838c2ecf20Sopenharmony_ci return 0; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* TODO: always do PIO fallback */ 3868c2ecf20Sopenharmony_ci if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA) 3878c2ecf20Sopenharmony_ci return -1; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci ide_set_max_pio(drive); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci return -1; 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ciint ide_set_dma(ide_drive_t *drive) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci int rc; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci /* 3998c2ecf20Sopenharmony_ci * Force DMAing for the beginning of the check. 4008c2ecf20Sopenharmony_ci * Some chipsets appear to do interesting 4018c2ecf20Sopenharmony_ci * things, if not checked and cleared. 4028c2ecf20Sopenharmony_ci * PARANOIA!!! 4038c2ecf20Sopenharmony_ci */ 4048c2ecf20Sopenharmony_ci ide_dma_off_quietly(drive); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci rc = ide_dma_check(drive); 4078c2ecf20Sopenharmony_ci if (rc) 4088c2ecf20Sopenharmony_ci return rc; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci ide_dma_on(drive); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci return 0; 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_civoid ide_check_dma_crc(ide_drive_t *drive) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci u8 mode; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci ide_dma_off_quietly(drive); 4208c2ecf20Sopenharmony_ci drive->crc_count = 0; 4218c2ecf20Sopenharmony_ci mode = drive->current_speed; 4228c2ecf20Sopenharmony_ci /* 4238c2ecf20Sopenharmony_ci * Don't try non Ultra-DMA modes without iCRC's. Force the 4248c2ecf20Sopenharmony_ci * device to PIO and make the user enable SWDMA/MWDMA modes. 4258c2ecf20Sopenharmony_ci */ 4268c2ecf20Sopenharmony_ci if (mode > XFER_UDMA_0 && mode <= XFER_UDMA_7) 4278c2ecf20Sopenharmony_ci mode--; 4288c2ecf20Sopenharmony_ci else 4298c2ecf20Sopenharmony_ci mode = XFER_PIO_4; 4308c2ecf20Sopenharmony_ci ide_set_xfer_rate(drive, mode); 4318c2ecf20Sopenharmony_ci if (drive->current_speed >= XFER_SW_DMA_0) 4328c2ecf20Sopenharmony_ci ide_dma_on(drive); 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_civoid ide_dma_lost_irq(ide_drive_t *drive) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: DMA interrupt recovery\n", drive->name); 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_dma_lost_irq); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci/* 4428c2ecf20Sopenharmony_ci * un-busy the port etc, and clear any pending DMA status. we want to 4438c2ecf20Sopenharmony_ci * retry the current request in pio mode instead of risking tossing it 4448c2ecf20Sopenharmony_ci * all away 4458c2ecf20Sopenharmony_ci */ 4468c2ecf20Sopenharmony_ciide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 4498c2ecf20Sopenharmony_ci const struct ide_dma_ops *dma_ops = hwif->dma_ops; 4508c2ecf20Sopenharmony_ci struct ide_cmd *cmd = &hwif->cmd; 4518c2ecf20Sopenharmony_ci ide_startstop_t ret = ide_stopped; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci /* 4548c2ecf20Sopenharmony_ci * end current dma transaction 4558c2ecf20Sopenharmony_ci */ 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (error < 0) { 4588c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: DMA timeout error\n", drive->name); 4598c2ecf20Sopenharmony_ci drive->waiting_for_dma = 0; 4608c2ecf20Sopenharmony_ci (void)dma_ops->dma_end(drive); 4618c2ecf20Sopenharmony_ci ide_dma_unmap_sg(drive, cmd); 4628c2ecf20Sopenharmony_ci ret = ide_error(drive, "dma timeout error", 4638c2ecf20Sopenharmony_ci hwif->tp_ops->read_status(hwif)); 4648c2ecf20Sopenharmony_ci } else { 4658c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name); 4668c2ecf20Sopenharmony_ci if (dma_ops->dma_clear) 4678c2ecf20Sopenharmony_ci dma_ops->dma_clear(drive); 4688c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name); 4698c2ecf20Sopenharmony_ci if (dma_ops->dma_test_irq(drive) == 0) { 4708c2ecf20Sopenharmony_ci ide_dump_status(drive, "DMA timeout", 4718c2ecf20Sopenharmony_ci hwif->tp_ops->read_status(hwif)); 4728c2ecf20Sopenharmony_ci drive->waiting_for_dma = 0; 4738c2ecf20Sopenharmony_ci (void)dma_ops->dma_end(drive); 4748c2ecf20Sopenharmony_ci ide_dma_unmap_sg(drive, cmd); 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci /* 4798c2ecf20Sopenharmony_ci * disable dma for now, but remember that we did so because of 4808c2ecf20Sopenharmony_ci * a timeout -- we'll reenable after we finish this next request 4818c2ecf20Sopenharmony_ci * (or rather the first chunk of it) in pio. 4828c2ecf20Sopenharmony_ci */ 4838c2ecf20Sopenharmony_ci drive->dev_flags |= IDE_DFLAG_DMA_PIO_RETRY; 4848c2ecf20Sopenharmony_ci drive->retry_pio++; 4858c2ecf20Sopenharmony_ci ide_dma_off_quietly(drive); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* 4888c2ecf20Sopenharmony_ci * make sure request is sane 4898c2ecf20Sopenharmony_ci */ 4908c2ecf20Sopenharmony_ci if (hwif->rq) 4918c2ecf20Sopenharmony_ci scsi_req(hwif->rq)->result = 0; 4928c2ecf20Sopenharmony_ci return ret; 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_civoid ide_release_dma_engine(ide_hwif_t *hwif) 4968c2ecf20Sopenharmony_ci{ 4978c2ecf20Sopenharmony_ci if (hwif->dmatable_cpu) { 4988c2ecf20Sopenharmony_ci int prd_size = hwif->prd_max_nents * hwif->prd_ent_size; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci dma_free_coherent(hwif->dev, prd_size, 5018c2ecf20Sopenharmony_ci hwif->dmatable_cpu, hwif->dmatable_dma); 5028c2ecf20Sopenharmony_ci hwif->dmatable_cpu = NULL; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_release_dma_engine); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ciint ide_allocate_dma_engine(ide_hwif_t *hwif) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci int prd_size; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci if (hwif->prd_max_nents == 0) 5128c2ecf20Sopenharmony_ci hwif->prd_max_nents = PRD_ENTRIES; 5138c2ecf20Sopenharmony_ci if (hwif->prd_ent_size == 0) 5148c2ecf20Sopenharmony_ci hwif->prd_ent_size = PRD_BYTES; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci prd_size = hwif->prd_max_nents * hwif->prd_ent_size; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci hwif->dmatable_cpu = dma_alloc_coherent(hwif->dev, prd_size, 5198c2ecf20Sopenharmony_ci &hwif->dmatable_dma, 5208c2ecf20Sopenharmony_ci GFP_ATOMIC); 5218c2ecf20Sopenharmony_ci if (hwif->dmatable_cpu == NULL) { 5228c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: unable to allocate PRD table\n", 5238c2ecf20Sopenharmony_ci hwif->name); 5248c2ecf20Sopenharmony_ci return -ENOMEM; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci return 0; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_allocate_dma_engine); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ciint ide_dma_prepare(ide_drive_t *drive, struct ide_cmd *cmd) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci const struct ide_dma_ops *dma_ops = drive->hwif->dma_ops; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0 || 5368c2ecf20Sopenharmony_ci (dma_ops->dma_check && dma_ops->dma_check(drive, cmd))) 5378c2ecf20Sopenharmony_ci goto out; 5388c2ecf20Sopenharmony_ci ide_map_sg(drive, cmd); 5398c2ecf20Sopenharmony_ci if (ide_dma_map_sg(drive, cmd) == 0) 5408c2ecf20Sopenharmony_ci goto out_map; 5418c2ecf20Sopenharmony_ci if (dma_ops->dma_setup(drive, cmd)) 5428c2ecf20Sopenharmony_ci goto out_dma_unmap; 5438c2ecf20Sopenharmony_ci drive->waiting_for_dma = 1; 5448c2ecf20Sopenharmony_ci return 0; 5458c2ecf20Sopenharmony_ciout_dma_unmap: 5468c2ecf20Sopenharmony_ci ide_dma_unmap_sg(drive, cmd); 5478c2ecf20Sopenharmony_ciout_map: 5488c2ecf20Sopenharmony_ci ide_map_sg(drive, cmd); 5498c2ecf20Sopenharmony_ciout: 5508c2ecf20Sopenharmony_ci return 1; 5518c2ecf20Sopenharmony_ci} 552