dmaengine: at_xdmac: rework slave configuration part

Rework slave configuration part in order to more report wrong errors
about the configuration.
Only maxburst and addr width values are checked when doing the slave
configuration. The validity of the channel configuration is done at
prepare time.

Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
Cc: stable@vger.kernel.org # 4.0 and later
Signed-off-by: Vinod Koul <vinod.koul@intel.com>

authored by Ludovic Desroches and committed by Vinod Koul 765c37d8 4c374fc7

Changed files
+96 -60
drivers
+96 -60
drivers/dma/at_xdmac.c
··· 174 174 #define AT_XDMAC_MBR_UBC_NDV3 (0x3 << 27) /* Next Descriptor View 3 */ 175 175 176 176 #define AT_XDMAC_MAX_CHAN 0x20 177 + #define AT_XDMAC_MAX_CSIZE 16 /* 16 data */ 178 + #define AT_XDMAC_MAX_DWIDTH 8 /* 64 bits */ 177 179 178 180 #define AT_XDMAC_DMA_BUSWIDTHS\ 179 181 (BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) |\ ··· 194 192 struct dma_chan chan; 195 193 void __iomem *ch_regs; 196 194 u32 mask; /* Channel Mask */ 197 - u32 cfg[2]; /* Channel Configuration Register */ 198 - #define AT_XDMAC_DEV_TO_MEM_CFG 0 /* Predifined dev to mem channel conf */ 199 - #define AT_XDMAC_MEM_TO_DEV_CFG 1 /* Predifined mem to dev channel conf */ 195 + u32 cfg; /* Channel Configuration Register */ 200 196 u8 perid; /* Peripheral ID */ 201 197 u8 perif; /* Peripheral Interface */ 202 198 u8 memif; /* Memory Interface */ 203 - u32 per_src_addr; 204 - u32 per_dst_addr; 205 199 u32 save_cc; 206 200 u32 save_cim; 207 201 u32 save_cnda; 208 202 u32 save_cndc; 209 203 unsigned long status; 210 204 struct tasklet_struct tasklet; 205 + struct dma_slave_config sconfig; 211 206 212 207 spinlock_t lock; 213 208 ··· 494 495 return chan; 495 496 } 496 497 498 + static int at_xdmac_compute_chan_conf(struct dma_chan *chan, 499 + enum dma_transfer_direction direction) 500 + { 501 + struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); 502 + int csize, dwidth; 503 + 504 + if (direction == DMA_DEV_TO_MEM) { 505 + atchan->cfg = 506 + AT91_XDMAC_DT_PERID(atchan->perid) 507 + | AT_XDMAC_CC_DAM_INCREMENTED_AM 508 + | AT_XDMAC_CC_SAM_FIXED_AM 509 + | AT_XDMAC_CC_DIF(atchan->memif) 510 + | AT_XDMAC_CC_SIF(atchan->perif) 511 + | AT_XDMAC_CC_SWREQ_HWR_CONNECTED 512 + | AT_XDMAC_CC_DSYNC_PER2MEM 513 + | AT_XDMAC_CC_MBSIZE_SIXTEEN 514 + | AT_XDMAC_CC_TYPE_PER_TRAN; 515 + csize = ffs(atchan->sconfig.src_maxburst) - 1; 516 + if (csize < 0) { 517 + dev_err(chan2dev(chan), "invalid src maxburst value\n"); 518 + return -EINVAL; 519 + } 520 + atchan->cfg |= AT_XDMAC_CC_CSIZE(csize); 521 + dwidth = ffs(atchan->sconfig.src_addr_width) - 1; 522 + if (dwidth < 0) { 523 + dev_err(chan2dev(chan), "invalid src addr width value\n"); 524 + return -EINVAL; 525 + } 526 + atchan->cfg |= AT_XDMAC_CC_DWIDTH(dwidth); 527 + } else if (direction == DMA_MEM_TO_DEV) { 528 + atchan->cfg = 529 + AT91_XDMAC_DT_PERID(atchan->perid) 530 + | AT_XDMAC_CC_DAM_FIXED_AM 531 + | AT_XDMAC_CC_SAM_INCREMENTED_AM 532 + | AT_XDMAC_CC_DIF(atchan->perif) 533 + | AT_XDMAC_CC_SIF(atchan->memif) 534 + | AT_XDMAC_CC_SWREQ_HWR_CONNECTED 535 + | AT_XDMAC_CC_DSYNC_MEM2PER 536 + | AT_XDMAC_CC_MBSIZE_SIXTEEN 537 + | AT_XDMAC_CC_TYPE_PER_TRAN; 538 + csize = ffs(atchan->sconfig.dst_maxburst) - 1; 539 + if (csize < 0) { 540 + dev_err(chan2dev(chan), "invalid src maxburst value\n"); 541 + return -EINVAL; 542 + } 543 + atchan->cfg |= AT_XDMAC_CC_CSIZE(csize); 544 + dwidth = ffs(atchan->sconfig.dst_addr_width) - 1; 545 + if (dwidth < 0) { 546 + dev_err(chan2dev(chan), "invalid dst addr width value\n"); 547 + return -EINVAL; 548 + } 549 + atchan->cfg |= AT_XDMAC_CC_DWIDTH(dwidth); 550 + } 551 + 552 + dev_dbg(chan2dev(chan), "%s: cfg=0x%08x\n", __func__, atchan->cfg); 553 + 554 + return 0; 555 + } 556 + 557 + /* 558 + * Only check that maxburst and addr width values are supported by the 559 + * the controller but not that the configuration is good to perform the 560 + * transfer since we don't know the direction at this stage. 561 + */ 562 + static int at_xdmac_check_slave_config(struct dma_slave_config *sconfig) 563 + { 564 + if ((sconfig->src_maxburst > AT_XDMAC_MAX_CSIZE) 565 + || (sconfig->dst_maxburst > AT_XDMAC_MAX_CSIZE)) 566 + return -EINVAL; 567 + 568 + if ((sconfig->src_addr_width > AT_XDMAC_MAX_DWIDTH) 569 + || (sconfig->dst_addr_width > AT_XDMAC_MAX_DWIDTH)) 570 + return -EINVAL; 571 + 572 + return 0; 573 + } 574 + 497 575 static int at_xdmac_set_slave_config(struct dma_chan *chan, 498 576 struct dma_slave_config *sconfig) 499 577 { 500 578 struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); 501 - u8 dwidth; 502 - int csize; 503 579 504 - atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG] = 505 - AT91_XDMAC_DT_PERID(atchan->perid) 506 - | AT_XDMAC_CC_DAM_INCREMENTED_AM 507 - | AT_XDMAC_CC_SAM_FIXED_AM 508 - | AT_XDMAC_CC_DIF(atchan->memif) 509 - | AT_XDMAC_CC_SIF(atchan->perif) 510 - | AT_XDMAC_CC_SWREQ_HWR_CONNECTED 511 - | AT_XDMAC_CC_DSYNC_PER2MEM 512 - | AT_XDMAC_CC_MBSIZE_SIXTEEN 513 - | AT_XDMAC_CC_TYPE_PER_TRAN; 514 - csize = at_xdmac_csize(sconfig->src_maxburst); 515 - if (csize < 0) { 516 - dev_err(chan2dev(chan), "invalid src maxburst value\n"); 580 + if (at_xdmac_check_slave_config(sconfig)) { 581 + dev_err(chan2dev(chan), "invalid slave configuration\n"); 517 582 return -EINVAL; 518 583 } 519 - atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG] |= AT_XDMAC_CC_CSIZE(csize); 520 - dwidth = ffs(sconfig->src_addr_width) - 1; 521 - atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG] |= AT_XDMAC_CC_DWIDTH(dwidth); 522 584 523 - 524 - atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG] = 525 - AT91_XDMAC_DT_PERID(atchan->perid) 526 - | AT_XDMAC_CC_DAM_FIXED_AM 527 - | AT_XDMAC_CC_SAM_INCREMENTED_AM 528 - | AT_XDMAC_CC_DIF(atchan->perif) 529 - | AT_XDMAC_CC_SIF(atchan->memif) 530 - | AT_XDMAC_CC_SWREQ_HWR_CONNECTED 531 - | AT_XDMAC_CC_DSYNC_MEM2PER 532 - | AT_XDMAC_CC_MBSIZE_SIXTEEN 533 - | AT_XDMAC_CC_TYPE_PER_TRAN; 534 - csize = at_xdmac_csize(sconfig->dst_maxburst); 535 - if (csize < 0) { 536 - dev_err(chan2dev(chan), "invalid src maxburst value\n"); 537 - return -EINVAL; 538 - } 539 - atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG] |= AT_XDMAC_CC_CSIZE(csize); 540 - dwidth = ffs(sconfig->dst_addr_width) - 1; 541 - atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG] |= AT_XDMAC_CC_DWIDTH(dwidth); 542 - 543 - /* Src and dst addr are needed to configure the link list descriptor. */ 544 - atchan->per_src_addr = sconfig->src_addr; 545 - atchan->per_dst_addr = sconfig->dst_addr; 546 - 547 - dev_dbg(chan2dev(chan), 548 - "%s: cfg[dev2mem]=0x%08x, cfg[mem2dev]=0x%08x, per_src_addr=0x%08x, per_dst_addr=0x%08x\n", 549 - __func__, atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG], 550 - atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG], 551 - atchan->per_src_addr, atchan->per_dst_addr); 585 + memcpy(&atchan->sconfig, sconfig, sizeof(atchan->sconfig)); 552 586 553 587 return 0; 554 588 } ··· 615 583 /* Protect dma_sconfig field that can be modified by set_slave_conf. */ 616 584 spin_lock_irqsave(&atchan->lock, irqflags); 617 585 586 + if (at_xdmac_compute_chan_conf(chan, direction)) 587 + goto spin_unlock; 588 + 618 589 /* Prepare descriptors. */ 619 590 for_each_sg(sgl, sg, sg_len, i) { 620 591 struct at_xdmac_desc *desc = NULL; ··· 642 607 643 608 /* Linked list descriptor setup. */ 644 609 if (direction == DMA_DEV_TO_MEM) { 645 - desc->lld.mbr_sa = atchan->per_src_addr; 610 + desc->lld.mbr_sa = atchan->sconfig.src_addr; 646 611 desc->lld.mbr_da = mem; 647 - desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG]; 648 612 } else { 649 613 desc->lld.mbr_sa = mem; 650 - desc->lld.mbr_da = atchan->per_dst_addr; 651 - desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG]; 614 + desc->lld.mbr_da = atchan->sconfig.dst_addr; 652 615 } 616 + desc->lld.mbr_cfg = atchan->cfg; 653 617 dwidth = at_xdmac_get_dwidth(desc->lld.mbr_cfg); 654 618 fixed_dwidth = IS_ALIGNED(len, 1 << dwidth) 655 619 ? at_xdmac_get_dwidth(desc->lld.mbr_cfg) ··· 717 683 return NULL; 718 684 } 719 685 686 + if (at_xdmac_compute_chan_conf(chan, direction)) 687 + return NULL; 688 + 720 689 for (i = 0; i < periods; i++) { 721 690 struct at_xdmac_desc *desc = NULL; 722 691 ··· 738 701 __func__, desc, &desc->tx_dma_desc.phys); 739 702 740 703 if (direction == DMA_DEV_TO_MEM) { 741 - desc->lld.mbr_sa = atchan->per_src_addr; 704 + desc->lld.mbr_sa = atchan->sconfig.src_addr; 742 705 desc->lld.mbr_da = buf_addr + i * period_len; 743 - desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG]; 744 706 } else { 745 707 desc->lld.mbr_sa = buf_addr + i * period_len; 746 - desc->lld.mbr_da = atchan->per_dst_addr; 747 - desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG]; 708 + desc->lld.mbr_da = atchan->sconfig.dst_addr; 748 709 } 710 + desc->lld.mbr_cfg = atchan->cfg; 749 711 desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV1 750 712 | AT_XDMAC_MBR_UBC_NDEN 751 713 | AT_XDMAC_MBR_UBC_NSEN