commit: http://blackfin.uclinux.org/git/?p=linux-kernel;a=commitdiff;h=f160f4dbf02264306c3c680e5aee552db78d5549 branch: http://blackfin.uclinux.org/git/?p=linux-kernel;a=shortlog;h=refs/heads/trunk
Make all 4 crc mode pass test suite. Signed-off-by: Sonic Zhang <[email protected]> Signed-off-by: Bob Liu <[email protected]> --- drivers/char/bfin_crc.c | 161 ++++++++++++++++++++++++++--------------------- 1 files changed, 90 insertions(+), 71 deletions(-) diff --git a/drivers/char/bfin_crc.c b/drivers/char/bfin_crc.c index 44a85da..3c44ff5 100644 --- a/drivers/char/bfin_crc.c +++ b/drivers/char/bfin_crc.c @@ -27,7 +27,7 @@ static LIST_HEAD(bfin_crc_list); -static void bfin_crc_config_dma(unsigned long dma_ch, unsigned long addr, +static void bfin_crc_config_dma(unsigned long dma_ch, unsigned char *addr, unsigned long size, unsigned long dma_config, int mod_dir) { unsigned int dma_count; @@ -36,11 +36,11 @@ static void bfin_crc_config_dma(unsigned long dma_ch, unsigned long addr, dma_config |= PSIZE_32; - if (addr % 4 == 0) { + if ((unsigned long)addr % 4 == 0) { dma_config |= WDSIZE_32; dma_count = size >> 2; dma_shift = 2; - } else if (addr % 2 == 0) { + } else if ((unsigned long)addr % 2 == 0) { dma_config |= WDSIZE_16; dma_count = size >> 1; dma_shift = 1; @@ -50,17 +50,15 @@ static void bfin_crc_config_dma(unsigned long dma_ch, unsigned long addr, dma_shift = 0; } - /* If the two memory regions have a chance of overlapping, make - * sure the memcpy still works as expected. Do this by having the - * copy run backwards instead. - */ dma_mod = (1 << dma_shift) * mod_dir; - addr += size + dma_mod; + if (mod_dir == -1) + addr += size + dma_mod; - set_dma_start_addr(dma_ch, addr); + set_dma_start_addr(dma_ch, (unsigned long)addr); set_dma_x_count(dma_ch, dma_count); set_dma_x_modify(dma_ch, dma_mod); set_dma_config(dma_ch, dma_config); + SSYNC(); enable_dma(dma_ch); } @@ -69,102 +67,122 @@ static int bfin_crc_run(struct bfin_crc *crc, unsigned int opmode, struct crc_in int ret = 0; unsigned long control; unsigned int timeout = 100000; - int mod_dir; + int mod_dir = 1; - if (info->crc_datasize == 0) + if (info->datasize == 0) return 0; - else if (info->crc_datasize % 4 != 0) { + else if (info->datasize % 4 != 0) { dev_info(crc->mdev.this_device, "CRC data size should be multiply of 4 bytes.\n"); - return -EFAULT; + return -EINVAL; } /* config CRC */ - crc->regs->poly = info->crc_poly; - SSYNC(); - - if (opmode == MODE_DATA_FILL) - crc->regs->fillval = info->crc_fillval; - else - crc->regs->compare = info->crc_compare; - - control = (opmode & OPMODE) << OPMODE_OFFSET; - control |= info->bitmirr << BITMIRR_OFFSET; - control |= info->bytmirr << BYTMIRR_OFFSET; - control |= info->w16swp << W16SWP_OFFSET; - control |= info->fdsel << FDSEL_OFFSET; - control |= info->rsltmirr << RSLTMIRR_OFFSET; - control |= info->polymirr << POLYMIRR_OFFSET; - control |= info->cmpmirr << CMPMIRR_OFFSET; + control = opmode << OPMODE_OFFSET; + control |= (info->bitmirr << BITMIRR_OFFSET); + control |= (info->bytmirr << BYTMIRR_OFFSET); + control |= (info->w16swp << W16SWP_OFFSET); + control |= (info->fdsel << FDSEL_OFFSET); + control |= (info->rsltmirr << RSLTMIRR_OFFSET); + control |= (info->polymirr << POLYMIRR_OFFSET); + control |= (info->cmpmirr << CMPMIRR_OFFSET); + control |= AUTOCLRZ; if (opmode == MODE_DMACPY_CRC) control |= OBRSTALL; crc->regs->control = control; - crc->regs->datacnt = info->crc_datasize >> 2; + SSYNC(); - while (!(crc->regs->status & LUTDONE) && (--timeout) > 0) - cpu_relax(); + if (opmode == MODE_CALC_CRC || opmode == MODE_DMACPY_CRC) { + crc->regs->poly = info->crc_poly; + SSYNC(); + + while (!(crc->regs->status & LUTDONE) && (--timeout) > 0) + cpu_relax(); - if (!timeout) { - dev_dbg(crc->mdev.this_device, "Timeout when generating LUT.\n"); - return -EBUSY; + if (!timeout) { + dev_dbg(crc->mdev.this_device, "Timeout when generating LUT.\n"); + return -EBUSY; + } } + crc->regs->datacntrld = 0; + crc->regs->datacnt = info->datasize >> 2; + crc->regs->compare = info->crc_compare; + /* setup CRC interrupts */ crc->regs->intrenset = CMPERRI | DCNTEXPI; SSYNC(); - /* setup CRC DMA */ + /* setup CRC receive DMA */ switch (opmode) { - case MODE_CALC_CRC: - case MODE_DATA_VERIFY: - flush_dcache_range(info->in_addr, info->in_addr + info->crc_datasize); - bfin_crc_config_dma(crc->dma_ch_src, info->in_addr, - info->crc_datasize, 0, 1); - break; - case MODE_DMACPY_CRC: - flush_dcache_range(info->in_addr, info->in_addr + info->crc_datasize); - invalidate_dcache_range(info->out_addr, info->out_addr + info->crc_datasize); - if (info->out_addr < info->in_addr + info->crc_datasize) - mod_dir = -1; - else - mod_dir = 1; - bfin_crc_config_dma(crc->dma_ch_src, info->in_addr, - info->crc_datasize, 0, mod_dir); - bfin_crc_config_dma(crc->dma_ch_dest, info->out_addr, - info->crc_datasize, WNR, mod_dir); - break; - case MODE_DATA_FILL: - invalidate_dcache_range(info->out_addr, info->out_addr + info->crc_datasize); - bfin_crc_config_dma(crc->dma_ch_dest, info->out_addr, - info->crc_datasize, WNR, 1); - break; - default: - goto out; + case MODE_DMACPY_CRC: + invalidate_dcache_range((unsigned long)info->out_addr, + (unsigned long)(info->out_addr + info->datasize)); + if (info->out_addr < info->in_addr + info->datasize) + mod_dir = -1; + bfin_crc_config_dma(crc->dma_ch_dest, info->out_addr, + info->datasize, WNR, mod_dir); + break; + case MODE_DATA_FILL: + crc->regs->fillval = info->val_fill; + invalidate_dcache_range((unsigned long)info->out_addr, + (unsigned long)(info->out_addr + info->datasize)); + bfin_crc_config_dma(crc->dma_ch_dest, info->out_addr, + info->datasize, WNR, 1); + break; } /* enable CRC operation */ crc->regs->control |= BLKEN; SSYNC(); + /* setup CRC transfer DMA */ + switch (opmode) { + case MODE_CALC_CRC: + case MODE_DATA_VERIFY: + flush_dcache_range((unsigned long)info->in_addr, + (unsigned long)(info->in_addr + info->datasize)); + bfin_crc_config_dma(crc->dma_ch_src, info->in_addr, + info->datasize, 0, 1); + break; + case MODE_DMACPY_CRC: + flush_dcache_range((unsigned long)info->in_addr, + (unsigned long)(info->in_addr + info->datasize)); + bfin_crc_config_dma(crc->dma_ch_src, info->in_addr, + info->datasize, 0, mod_dir); + break; + } + /* wait for completion */ - ret = wait_for_completion_interruptible(&crc->c); - if (ret < 0) { + if ((ret = wait_for_completion_interruptible(&crc->c)) < 0) { dev_dbg(crc->mdev.this_device, "Completion waiting is interrupted.\n"); goto out; } - - if (opmode == MODE_DMACPY_CRC || MODE_DATA_FILL) + if (opmode == MODE_DMACPY_CRC || opmode == MODE_DATA_FILL) while (crc->regs->status & OBR) cpu_relax(); /* prepare results */ - info->crc_result = crc->regs->result; - crc->regs->control = 0; - SSYNC(); + switch (opmode) { + case MODE_CALC_CRC: + case MODE_DMACPY_CRC: + info->crc_result = crc->regs->result; + break; + case MODE_DATA_VERIFY: + info->pos_verify = (crc->regs->status & CMPERR) ? crc->regs->datacntcap : 0; + break; + }; + +out: + clear_dma_irqstat(crc->dma_ch_src); + clear_dma_irqstat(crc->dma_ch_dest); disable_dma(crc->dma_ch_src); disable_dma(crc->dma_ch_dest); -out: + crc->regs->intrenclr = CMPERRI | DCNTEXPI; + crc->regs->status = CMPERRI | DCNTEXPI; + crc->regs->control = 0; + SSYNC(); return ret; } @@ -178,7 +196,8 @@ static irqreturn_t bfin_crc_handler(int irq, void *dev_id) if (crc->regs->status & DCNTEXP) { crc->regs->status = DCNTEXP; SSYNC(); - complete(&crc->c); + if (crc->regs->control | BLKEN) + complete(&crc->c); return IRQ_HANDLED; } else return IRQ_NONE; @@ -309,7 +328,7 @@ static long bfin_crc_ioctl(struct file *filp, ret = -ENOTTY; } - if (ret > 0 && copy_to_user(argp, &bfin_crc_info, sizeof(bfin_crc_info))) + if (ret >= 0 && copy_to_user(argp, &bfin_crc_info, sizeof(bfin_crc_info))) ret = -EFAULT; out:
_______________________________________________ Linux-kernel-commits mailing list [email protected] https://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits
