diff options
Diffstat (limited to 'drivers/ide/tx4939ide.c')
| -rw-r--r-- | drivers/ide/tx4939ide.c | 289 |
1 files changed, 83 insertions, 206 deletions
diff --git a/drivers/ide/tx4939ide.c b/drivers/ide/tx4939ide.c index bafb7d1a22e..4ecdee5eca8 100644 --- a/drivers/ide/tx4939ide.c +++ b/drivers/ide/tx4939ide.c @@ -18,6 +18,8 @@ #include <linux/io.h> #include <linux/scatterlist.h> +#include <asm/ide.h> + #define MODNAME "tx4939ide" /* ATA Shadow Registers (8-bit except for Data which is 16-bit) */ @@ -102,17 +104,17 @@ static void tx4939ide_writeb(u8 val, void __iomem *base, u32 reg) #define TX4939IDE_BASE(hwif) ((void __iomem *)(hwif)->extra_base) -static void tx4939ide_set_pio_mode(ide_drive_t *drive, const u8 pio) +static void tx4939ide_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) { - ide_hwif_t *hwif = drive->hwif; int is_slave = drive->dn; u32 mask, val; + const u8 pio = drive->pio_mode - XFER_PIO_0; u8 safe = pio; ide_drive_t *pair; pair = ide_get_pair_dev(drive); if (pair) - safe = min(safe, ide_get_best_pio_mode(pair, 255, 4)); + safe = min_t(u8, safe, pair->pio_mode - XFER_PIO_0); /* * Update Command Transfer Mode for master/slave and Data * Transfer Mode for this drive. @@ -123,10 +125,10 @@ static void tx4939ide_set_pio_mode(ide_drive_t *drive, const u8 pio) /* tx4939ide_tf_load_fixup() will set the Sys_Ctl register */ } -static void tx4939ide_set_dma_mode(ide_drive_t *drive, const u8 mode) +static void tx4939ide_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) { - ide_hwif_t *hwif = drive->hwif; u32 mask, val; + const u8 mode = drive->dma_mode; /* Update Data Transfer Mode for this drive. */ if (mode >= XFER_UDMA_0) @@ -230,7 +232,7 @@ static u8 tx4939ide_clear_dma_status(void __iomem *base) #ifdef __BIG_ENDIAN /* custom ide_build_dmatable to handle swapped layout */ -static int tx4939ide_build_dmatable(ide_drive_t *drive, struct request *rq) +static int tx4939ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) { ide_hwif_t *hwif = drive->hwif; u32 *table = (u32 *)hwif->dmatable_cpu; @@ -238,11 +240,7 @@ static int tx4939ide_build_dmatable(ide_drive_t *drive, struct request *rq) int i; struct scatterlist *sg; - hwif->sg_nents = ide_build_sglist(drive, rq); - if (hwif->sg_nents == 0) - return 0; - - for_each_sg(hwif->sg_table, sg, hwif->sg_nents, i) { + for_each_sg(hwif->sg_table, sg, cmd->sg_nents, i) { u32 cur_addr, cur_len, bcount; cur_addr = sg_dma_address(sg); @@ -259,6 +257,12 @@ static int tx4939ide_build_dmatable(ide_drive_t *drive, struct request *rq) bcount = 0x10000 - (cur_addr & 0xffff); if (bcount > cur_len) bcount = cur_len; + /* + * This workaround for zero count seems required. + * (standard ide_build_dmatable does it too) + */ + if (bcount == 0x10000) + bcount = 0x8000; *table++ = bcount & 0xffff; *table++ = cur_addr; cur_addr += bcount; @@ -275,48 +279,36 @@ use_pio_instead: printk(KERN_ERR "%s: %s\n", drive->name, count ? "DMA table too small" : "empty DMA table?"); - ide_destroy_dmatable(drive); - return 0; /* revert to PIO for this request */ } #else #define tx4939ide_build_dmatable ide_build_dmatable #endif -static int tx4939ide_dma_setup(ide_drive_t *drive) +static int tx4939ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) { ide_hwif_t *hwif = drive->hwif; void __iomem *base = TX4939IDE_BASE(hwif); - struct request *rq = hwif->hwgroup->rq; - u8 reading; - int nent; - - if (rq_data_dir(rq)) - reading = 0; - else - reading = ATA_DMA_WR; + u8 rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 0 : ATA_DMA_WR; /* fall back to PIO! */ - nent = tx4939ide_build_dmatable(drive, rq); - if (!nent) { - ide_map_sg(drive, rq); + if (tx4939ide_build_dmatable(drive, cmd) == 0) return 1; - } /* PRD table */ tx4939ide_writel(hwif->dmatable_dma, base, TX4939IDE_PRD_Ptr); /* specify r/w */ - tx4939ide_writeb(reading, base, TX4939IDE_DMA_Cmd); + tx4939ide_writeb(rw, base, TX4939IDE_DMA_Cmd); /* clear INTR & ERROR flags */ tx4939ide_clear_dma_status(base); - drive->waiting_for_dma = 1; - tx4939ide_writew(SECTOR_SIZE / 2, base, drive->dn ? TX4939IDE_Xfer_Cnt_2 : TX4939IDE_Xfer_Cnt_1); - tx4939ide_writew(rq->nr_sectors, base, TX4939IDE_Sec_Cnt); + + tx4939ide_writew(blk_rq_sectors(cmd->rq), base, TX4939IDE_Sec_Cnt); + return 0; } @@ -327,8 +319,6 @@ static int tx4939ide_dma_end(ide_drive_t *drive) void __iomem *base = TX4939IDE_BASE(hwif); u16 ctl = tx4939ide_readw(base, TX4939IDE_Int_Ctl); - drive->waiting_for_dma = 0; - /* get DMA command mode */ dma_cmd = tx4939ide_readb(base, TX4939IDE_DMA_Cmd); /* stop DMA */ @@ -337,17 +327,15 @@ static int tx4939ide_dma_end(ide_drive_t *drive) /* read and clear the INTR & ERROR bits */ dma_stat = tx4939ide_clear_dma_status(base); - /* purge DMA mappings */ - ide_destroy_dmatable(drive); - /* verify good DMA status */ - wmb(); +#define CHECK_DMA_MASK (ATA_DMA_ACTIVE | ATA_DMA_ERR | ATA_DMA_INTR) - if ((dma_stat & (ATA_DMA_INTR | ATA_DMA_ERR | ATA_DMA_ACTIVE)) == 0 && + /* verify good DMA status */ + if ((dma_stat & CHECK_DMA_MASK) == 0 && (ctl & (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST)) == (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST)) /* INT_IDE lost... bug? */ return 0; - return ((dma_stat & (ATA_DMA_INTR | ATA_DMA_ERR | ATA_DMA_ACTIVE)) != + return ((dma_stat & CHECK_DMA_MASK) != ATA_DMA_INTR) ? 0x10 | dma_stat : 0; } @@ -391,6 +379,17 @@ static int tx4939ide_dma_test_irq(ide_drive_t *drive) return found; } +#ifdef __BIG_ENDIAN +static u8 tx4939ide_dma_sff_read_status(ide_hwif_t *hwif) +{ + void __iomem *base = TX4939IDE_BASE(hwif); + + return tx4939ide_readb(base, TX4939IDE_DMA_Stat); +} +#else +#define tx4939ide_dma_sff_read_status ide_dma_sff_read_status +#endif + static void tx4939ide_init_hwif(ide_hwif_t *hwif) { void __iomem *base = TX4939IDE_BASE(hwif); @@ -420,7 +419,7 @@ static int tx4939ide_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d) return ide_allocate_dma_engine(hwif); } -static void tx4939ide_tf_load_fixup(ide_drive_t *drive, ide_task_t *task) +static void tx4939ide_tf_load_fixup(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; void __iomem *base = TX4939IDE_BASE(hwif); @@ -430,126 +429,24 @@ static void tx4939ide_tf_load_fixup(ide_drive_t *drive, ide_task_t *task) * Fix ATA100 CORE System Control Register. (The write to the * Device/Head register may write wrong data to the System * Control Register) - * While Sys_Ctl is written here, selectproc is not needed. + * While Sys_Ctl is written here, dev_select() is not needed. */ tx4939ide_writew(sysctl, base, TX4939IDE_Sys_Ctl); } -#ifdef __BIG_ENDIAN - -static u8 tx4939ide_read_sff_dma_status(ide_hwif_t *hwif) +static void tx4939ide_tf_load(ide_drive_t *drive, struct ide_taskfile *tf, + u8 valid) { - void __iomem *base = TX4939IDE_BASE(hwif); - - return tx4939ide_readb(base, TX4939IDE_DMA_Stat); -} + ide_tf_load(drive, tf, valid); -/* custom iops (independent from SWAP_IO_SPACE) */ -static u8 tx4939ide_inb(unsigned long port) -{ - return __raw_readb((void __iomem *)port); + if (valid & IDE_VALID_DEVICE) + tx4939ide_tf_load_fixup(drive); } -static void tx4939ide_outb(u8 value, unsigned long port) -{ - __raw_writeb(value, (void __iomem *)port); -} - -static void tx4939ide_tf_load(ide_drive_t *drive, ide_task_t *task) -{ - ide_hwif_t *hwif = drive->hwif; - struct ide_io_ports *io_ports = &hwif->io_ports; - struct ide_taskfile *tf = &task->tf; - u8 HIHI = task->tf_flags & IDE_TFLAG_LBA48 ? 0xE0 : 0xEF; - - if (task->tf_flags & IDE_TFLAG_FLAGGED) - HIHI = 0xFF; - - if (task->tf_flags & IDE_TFLAG_OUT_DATA) { - u16 data = (tf->hob_data << 8) | tf->data; - - /* no endian swap */ - __raw_writew(data, (void __iomem *)io_ports->data_addr); - } - - if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE) - tx4939ide_outb(tf->hob_feature, io_ports->feature_addr); - if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT) - tx4939ide_outb(tf->hob_nsect, io_ports->nsect_addr); - if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL) - tx4939ide_outb(tf->hob_lbal, io_ports->lbal_addr); - if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM) - tx4939ide_outb(tf->hob_lbam, io_ports->lbam_addr); - if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH) - tx4939ide_outb(tf->hob_lbah, io_ports->lbah_addr); - - if (task->tf_flags & IDE_TFLAG_OUT_FEATURE) - tx4939ide_outb(tf->feature, io_ports->feature_addr); - if (task->tf_flags & IDE_TFLAG_OUT_NSECT) - tx4939ide_outb(tf->nsect, io_ports->nsect_addr); - if (task->tf_flags & IDE_TFLAG_OUT_LBAL) - tx4939ide_outb(tf->lbal, io_ports->lbal_addr); - if (task->tf_flags & IDE_TFLAG_OUT_LBAM) - tx4939ide_outb(tf->lbam, io_ports->lbam_addr); - if (task->tf_flags & IDE_TFLAG_OUT_LBAH) - tx4939ide_outb(tf->lbah, io_ports->lbah_addr); - - if (task->tf_flags & IDE_TFLAG_OUT_DEVICE) { - tx4939ide_outb((tf->device & HIHI) | drive->select, - io_ports->device_addr); - tx4939ide_tf_load_fixup(drive, task); - } -} - -static void tx4939ide_tf_read(ide_drive_t *drive, ide_task_t *task) -{ - ide_hwif_t *hwif = drive->hwif; - struct ide_io_ports *io_ports = &hwif->io_ports; - struct ide_taskfile *tf = &task->tf; - - if (task->tf_flags & IDE_TFLAG_IN_DATA) { - u16 data; - - /* no endian swap */ - data = __raw_readw((void __iomem *)io_ports->data_addr); - tf->data = data & 0xff; - tf->hob_data = (data >> 8) & 0xff; - } - - /* be sure we're looking at the low order bits */ - tx4939ide_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr); - - if (task->tf_flags & IDE_TFLAG_IN_FEATURE) - tf->feature = tx4939ide_inb(io_ports->feature_addr); - if (task->tf_flags & IDE_TFLAG_IN_NSECT) - tf->nsect = tx4939ide_inb(io_ports->nsect_addr); - if (task->tf_flags & IDE_TFLAG_IN_LBAL) - tf->lbal = tx4939ide_inb(io_ports->lbal_addr); - if (task->tf_flags & IDE_TFLAG_IN_LBAM) - tf->lbam = tx4939ide_inb(io_ports->lbam_addr); - if (task->tf_flags & IDE_TFLAG_IN_LBAH) - tf->lbah = tx4939ide_inb(io_ports->lbah_addr); - if (task->tf_flags & IDE_TFLAG_IN_DEVICE) - tf->device = tx4939ide_inb(io_ports->device_addr); - - if (task->tf_flags & IDE_TFLAG_LBA48) { - tx4939ide_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr); - - if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE) - tf->hob_feature = - tx4939ide_inb(io_ports->feature_addr); - if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT) - tf->hob_nsect = tx4939ide_inb(io_ports->nsect_addr); - if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL) - tf->hob_lbal = tx4939ide_inb(io_ports->lbal_addr); - if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM) - tf->hob_lbam = tx4939ide_inb(io_ports->lbam_addr); - if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH) - tf->hob_lbah = tx4939ide_inb(io_ports->lbah_addr); - } -} +#ifdef __BIG_ENDIAN -static void tx4939ide_input_data_swap(ide_drive_t *drive, struct request *rq, +/* custom iops (independent from SWAP_IO_SPACE) */ +static void tx4939ide_input_data_swap(ide_drive_t *drive, struct ide_cmd *cmd, void *buf, unsigned int len) { unsigned long port = drive->hwif->io_ports.data_addr; @@ -558,10 +455,10 @@ static void tx4939ide_input_data_swap(ide_drive_t *drive, struct request *rq, while (count--) *ptr++ = cpu_to_le16(__raw_readw((void __iomem *)port)); - __ide_flush_dcache_range((unsigned long)buf, count * 2); + __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2)); } -static void tx4939ide_output_data_swap(ide_drive_t *drive, struct request *rq, +static void tx4939ide_output_data_swap(ide_drive_t *drive, struct ide_cmd *cmd, void *buf, unsigned int len) { unsigned long port = drive->hwif->io_ports.data_addr; @@ -572,19 +469,18 @@ static void tx4939ide_output_data_swap(ide_drive_t *drive, struct request *rq, __raw_writew(le16_to_cpu(*ptr), (void __iomem *)port); ptr++; } - __ide_flush_dcache_range((unsigned long)buf, count * 2); + __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2)); } static const struct ide_tp_ops tx4939ide_tp_ops = { .exec_command = ide_exec_command, .read_status = ide_read_status, .read_altstatus = ide_read_altstatus, - .read_sff_dma_status = tx4939ide_read_sff_dma_status, - - .set_irq = ide_set_irq, + .write_devctl = ide_write_devctl, + .dev_select = ide_dev_select, .tf_load = tx4939ide_tf_load, - .tf_read = tx4939ide_tf_read, + .tf_read = ide_tf_read, .input_data = tx4939ide_input_data_swap, .output_data = tx4939ide_output_data_swap, @@ -592,21 +488,13 @@ static const struct ide_tp_ops tx4939ide_tp_ops = { #else /* __LITTLE_ENDIAN */ -static void tx4939ide_tf_load(ide_drive_t *drive, ide_task_t *task) -{ - ide_tf_load(drive, task); - if (task->tf_flags & IDE_TFLAG_OUT_DEVICE) - tx4939ide_tf_load_fixup(drive, task); -} - static const struct ide_tp_ops tx4939ide_tp_ops = { .exec_command = ide_exec_command, .read_status = ide_read_status, .read_altstatus = ide_read_altstatus, - .read_sff_dma_status = ide_read_sff_dma_status, - - .set_irq = ide_set_irq, + .write_devctl = ide_write_devctl, + .dev_select = ide_dev_select, .tf_load = tx4939ide_tf_load, .tf_read = ide_tf_read, @@ -617,39 +505,39 @@ static const struct ide_tp_ops tx4939ide_tp_ops = { #endif /* __LITTLE_ENDIAN */ static const struct ide_port_ops tx4939ide_port_ops = { - .set_pio_mode = tx4939ide_set_pio_mode, - .set_dma_mode = tx4939ide_set_dma_mode, - .clear_irq = tx4939ide_clear_irq, - .cable_detect = tx4939ide_cable_detect, + .set_pio_mode = tx4939ide_set_pio_mode, + .set_dma_mode = tx4939ide_set_dma_mode, + .clear_irq = tx4939ide_clear_irq, + .cable_detect = tx4939ide_cable_detect, }; static const struct ide_dma_ops tx4939ide_dma_ops = { - .dma_host_set = tx4939ide_dma_host_set, - .dma_setup = tx4939ide_dma_setup, - .dma_exec_cmd = ide_dma_exec_cmd, - .dma_start = ide_dma_start, - .dma_end = tx4939ide_dma_end, - .dma_test_irq = tx4939ide_dma_test_irq, - .dma_lost_irq = ide_dma_lost_irq, - .dma_timeout = ide_dma_timeout, + .dma_host_set = tx4939ide_dma_host_set, + .dma_setup = tx4939ide_dma_setup, + .dma_start = ide_dma_start, + .dma_end = tx4939ide_dma_end, + .dma_test_irq = tx4939ide_dma_test_irq, + .dma_lost_irq = ide_dma_lost_irq, + .dma_timer_expiry = ide_dma_sff_timer_expiry, + .dma_sff_read_status = tx4939ide_dma_sff_read_status, }; -static const struct ide_port_info tx4939ide_port_info __initdata = { - .init_hwif = tx4939ide_init_hwif, - .init_dma = tx4939ide_init_dma, - .port_ops = &tx4939ide_port_ops, - .dma_ops = &tx4939ide_dma_ops, - .tp_ops = &tx4939ide_tp_ops, - .host_flags = IDE_HFLAG_MMIO, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA5, +static const struct ide_port_info tx4939ide_port_info __initconst = { + .init_hwif = tx4939ide_init_hwif, + .init_dma = tx4939ide_init_dma, + .port_ops = &tx4939ide_port_ops, + .dma_ops = &tx4939ide_dma_ops, + .tp_ops = &tx4939ide_tp_ops, + .host_flags = IDE_HFLAG_MMIO, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA5, + .chipset = ide_generic, }; static int __init tx4939ide_probe(struct platform_device *pdev) { - hw_regs_t hw; - hw_regs_t *hws[] = { &hw, NULL, NULL, NULL }; + struct ide_hw hw, *hws[] = { &hw }; struct ide_host *host; struct resource *res; int irq, ret; @@ -663,10 +551,10 @@ static int __init tx4939ide_probe(struct platform_device *pdev) return -ENODEV; if (!devm_request_mem_region(&pdev->dev, res->start, - res->end - res->start + 1, "tx4938ide")) + resource_size(res), "tx4938ide")) return -EBUSY; mapbase = (unsigned long)devm_ioremap(&pdev->dev, res->start, - res->end - res->start + 1); + resource_size(res)); if (!mapbase) return -EBUSY; memset(&hw, 0, sizeof(hw)); @@ -692,7 +580,7 @@ static int __init tx4939ide_probe(struct platform_device *pdev) hw.dev = &pdev->dev; pr_info("TX4939 IDE interface (base %#lx, irq %d)\n", mapbase, irq); - host = ide_host_alloc(&tx4939ide_port_info, hws); + host = ide_host_alloc(&tx4939ide_port_info, hws, 1); if (!host) return -ENOMEM; /* use extra_base for base address of the all registers */ @@ -736,18 +624,7 @@ static struct platform_driver tx4939ide_driver = { .resume = tx4939ide_resume, }; -static int __init tx4939ide_init(void) -{ - return platform_driver_probe(&tx4939ide_driver, tx4939ide_probe); -} - -static void __exit tx4939ide_exit(void) -{ - platform_driver_unregister(&tx4939ide_driver); -} - -module_init(tx4939ide_init); -module_exit(tx4939ide_exit); +module_platform_driver_probe(tx4939ide_driver, tx4939ide_probe); MODULE_DESCRIPTION("TX4939 internal IDE driver"); MODULE_LICENSE("GPL"); |
