mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 21:21:41 +00:00
dmaengine fixes for 4.6-rc4
Okay we some driver fixes piled up, so time to get them up. This time we have some odd fixes in hsu, edma, omap and xilinx. Usual fixes and nothing special -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJXEnqKAAoJEHwUBw8lI4NH3ScP/RaxUP64cn4ttUM/G/13jWxs xpCtb25fRB7DcpqZpsAV84+NOGSJgJNOGKzWtfzu9aerUGcFiePwsv0V23ocC6oK OxLDHQdjR5WXXchTxMqugWzNb0NdaMXDA5hfM1CnStMj4ifZY5r9/l/0ndlrSgOf A1rZhg4TlbM1G1xnMYeDPwXRoHDs7k3eHM1XC9y5B50IPqMCsDwX4SODHX2vMu0H 6MbcturjfNN3hjr/ciTCMRYcab5q3Sv7UP31KSLA8LGzNojntj3shy2jLU6olQdn IT0nUA+K7eYk/4Q2HGIo9LhM33XLBuCSLKca2H6/xt8R6J0J6ASwbQqa1k4A1aSv n/jeQzlvgkGZA0Spat5Qms24NjtSbEllPcMkkoXXQsZctk4Hm2PRAOxVDFdXPt3C 0DMXHPnVhkOvamXqZYsvy/bqqUKDrHQvxW5kqtpn6W+B7bx5PPmPFRHtFWcbatsY 5y+D+3n0RNZqtKQ80M/3pRqpDh6MtrdfO9kuakS0BqpZZEFzZ5F0c2MzO93K2+3e lVzj1iwTXcYJTF/DTuPOKmu/g6BC3oqaLNXDlsUEODiczzZwcbEvDxa4Z1otzQn3 JJ0diVqQRAbIdvVSpSUPMwaqLn+s5r0Uz9tLRNdARNI22a6YgnOK3MEyq+9+OMxl rEA4ntRPxD2YzN7KfRY1 =bSYQ -----END PGP SIGNATURE----- Merge tag 'dmaengine-fix-4.6-rc4' of git://git.infradead.org/users/vkoul/slave-dma Pull dmaengine fixes from Vinod Koul: "This time we have some odd fixes in hsu, edma, omap and xilinx. Usual fixes and nothing special" * tag 'dmaengine-fix-4.6-rc4' of git://git.infradead.org/users/vkoul/slave-dma: dmaengine: dw: fix master selection dmaengine: edma: special case slot limit workaround dmaengine: edma: Remove dynamic TPTC power management feature dmaengine: vdma: don't crash when bad channel is requested dmaengine: omap-dma: Do not suppress interrupts for memcpy dmaengine: omap-dma: Fix polled channel completion detection and handling dmaengine: hsu: correct use of channel status register dmaengine: hsu: correct residue calculation of active descriptor dmaengine: hsu: set HSU_CH_MTSR to memory width
This commit is contained in:
commit
306a63bee1
@ -130,26 +130,14 @@ static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc)
|
||||
static void dwc_initialize(struct dw_dma_chan *dwc)
|
||||
{
|
||||
struct dw_dma *dw = to_dw_dma(dwc->chan.device);
|
||||
struct dw_dma_slave *dws = dwc->chan.private;
|
||||
u32 cfghi = DWC_CFGH_FIFO_MODE;
|
||||
u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority);
|
||||
|
||||
if (dwc->initialized == true)
|
||||
return;
|
||||
|
||||
if (dws) {
|
||||
/*
|
||||
* We need controller-specific data to set up slave
|
||||
* transfers.
|
||||
*/
|
||||
BUG_ON(!dws->dma_dev || dws->dma_dev != dw->dma.dev);
|
||||
|
||||
cfghi |= DWC_CFGH_DST_PER(dws->dst_id);
|
||||
cfghi |= DWC_CFGH_SRC_PER(dws->src_id);
|
||||
} else {
|
||||
cfghi |= DWC_CFGH_DST_PER(dwc->dst_id);
|
||||
cfghi |= DWC_CFGH_SRC_PER(dwc->src_id);
|
||||
}
|
||||
cfghi |= DWC_CFGH_DST_PER(dwc->dst_id);
|
||||
cfghi |= DWC_CFGH_SRC_PER(dwc->src_id);
|
||||
|
||||
channel_writel(dwc, CFG_LO, cfglo);
|
||||
channel_writel(dwc, CFG_HI, cfghi);
|
||||
@ -941,7 +929,7 @@ bool dw_dma_filter(struct dma_chan *chan, void *param)
|
||||
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
|
||||
struct dw_dma_slave *dws = param;
|
||||
|
||||
if (!dws || dws->dma_dev != chan->device->dev)
|
||||
if (dws->dma_dev != chan->device->dev)
|
||||
return false;
|
||||
|
||||
/* We have to copy data since dws can be temporary storage */
|
||||
@ -1165,6 +1153,14 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
|
||||
* doesn't mean what you think it means), and status writeback.
|
||||
*/
|
||||
|
||||
/*
|
||||
* We need controller-specific data to set up slave transfers.
|
||||
*/
|
||||
if (chan->private && !dw_dma_filter(chan, chan->private)) {
|
||||
dev_warn(chan2dev(chan), "Wrong controller-specific data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Enable controller here if needed */
|
||||
if (!dw->in_use)
|
||||
dw_dma_on(dw);
|
||||
@ -1226,6 +1222,14 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
list_splice_init(&dwc->free_list, &list);
|
||||
dwc->descs_allocated = 0;
|
||||
|
||||
/* Clear custom channel configuration */
|
||||
dwc->src_id = 0;
|
||||
dwc->dst_id = 0;
|
||||
|
||||
dwc->src_master = 0;
|
||||
dwc->dst_master = 0;
|
||||
|
||||
dwc->initialized = false;
|
||||
|
||||
/* Disable interrupts */
|
||||
|
@ -1238,6 +1238,7 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
|
||||
struct edma_desc *edesc;
|
||||
dma_addr_t src_addr, dst_addr;
|
||||
enum dma_slave_buswidth dev_width;
|
||||
bool use_intermediate = false;
|
||||
u32 burst;
|
||||
int i, ret, nslots;
|
||||
|
||||
@ -1279,8 +1280,21 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
|
||||
* but the synchronization is difficult to achieve with Cyclic and
|
||||
* cannot be guaranteed, so we error out early.
|
||||
*/
|
||||
if (nslots > MAX_NR_SG)
|
||||
return NULL;
|
||||
if (nslots > MAX_NR_SG) {
|
||||
/*
|
||||
* If the burst and period sizes are the same, we can put
|
||||
* the full buffer into a single period and activate
|
||||
* intermediate interrupts. This will produce interrupts
|
||||
* after each burst, which is also after each desired period.
|
||||
*/
|
||||
if (burst == period_len) {
|
||||
period_len = buf_len;
|
||||
nslots = 2;
|
||||
use_intermediate = true;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
edesc = kzalloc(sizeof(*edesc) + nslots * sizeof(edesc->pset[0]),
|
||||
GFP_ATOMIC);
|
||||
@ -1358,8 +1372,13 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
|
||||
/*
|
||||
* Enable period interrupt only if it is requested
|
||||
*/
|
||||
if (tx_flags & DMA_PREP_INTERRUPT)
|
||||
if (tx_flags & DMA_PREP_INTERRUPT) {
|
||||
edesc->pset[i].param.opt |= TCINTEN;
|
||||
|
||||
/* Also enable intermediate interrupts if necessary */
|
||||
if (use_intermediate)
|
||||
edesc->pset[i].param.opt |= ITCINTEN;
|
||||
}
|
||||
}
|
||||
|
||||
/* Place the cyclic channel to highest priority queue */
|
||||
@ -1570,32 +1589,6 @@ static irqreturn_t dma_ccerr_handler(int irq, void *data)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void edma_tc_set_pm_state(struct edma_tc *tc, bool enable)
|
||||
{
|
||||
struct platform_device *tc_pdev;
|
||||
int ret;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_OF) || !tc)
|
||||
return;
|
||||
|
||||
tc_pdev = of_find_device_by_node(tc->node);
|
||||
if (!tc_pdev) {
|
||||
pr_err("%s: TPTC device is not found\n", __func__);
|
||||
return;
|
||||
}
|
||||
if (!pm_runtime_enabled(&tc_pdev->dev))
|
||||
pm_runtime_enable(&tc_pdev->dev);
|
||||
|
||||
if (enable)
|
||||
ret = pm_runtime_get_sync(&tc_pdev->dev);
|
||||
else
|
||||
ret = pm_runtime_put_sync(&tc_pdev->dev);
|
||||
|
||||
if (ret < 0)
|
||||
pr_err("%s: pm_runtime_%s_sync() failed for %s\n", __func__,
|
||||
enable ? "get" : "put", dev_name(&tc_pdev->dev));
|
||||
}
|
||||
|
||||
/* Alloc channel resources */
|
||||
static int edma_alloc_chan_resources(struct dma_chan *chan)
|
||||
{
|
||||
@ -1632,8 +1625,6 @@ static int edma_alloc_chan_resources(struct dma_chan *chan)
|
||||
EDMA_CHAN_SLOT(echan->ch_num), chan->chan_id,
|
||||
echan->hw_triggered ? "HW" : "SW");
|
||||
|
||||
edma_tc_set_pm_state(echan->tc, true);
|
||||
|
||||
return 0;
|
||||
|
||||
err_slot:
|
||||
@ -1670,7 +1661,6 @@ static void edma_free_chan_resources(struct dma_chan *chan)
|
||||
echan->alloced = false;
|
||||
}
|
||||
|
||||
edma_tc_set_pm_state(echan->tc, false);
|
||||
echan->tc = NULL;
|
||||
echan->hw_triggered = false;
|
||||
|
||||
@ -2417,10 +2407,8 @@ static int edma_pm_suspend(struct device *dev)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ecc->num_channels; i++) {
|
||||
if (echan[i].alloced) {
|
||||
if (echan[i].alloced)
|
||||
edma_setup_interrupt(&echan[i], false);
|
||||
edma_tc_set_pm_state(echan[i].tc, false);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -2450,8 +2438,6 @@ static int edma_pm_resume(struct device *dev)
|
||||
|
||||
/* Set up channel -> slot mapping for the entry slot */
|
||||
edma_set_chmap(&echan[i], echan[i].slot[0]);
|
||||
|
||||
edma_tc_set_pm_state(echan[i].tc, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2475,7 +2461,8 @@ static struct platform_driver edma_driver = {
|
||||
|
||||
static int edma_tptc_probe(struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
return pm_runtime_get_sync(&pdev->dev);
|
||||
}
|
||||
|
||||
static struct platform_driver edma_tptc_driver = {
|
||||
|
@ -64,10 +64,10 @@ static void hsu_dma_chan_start(struct hsu_dma_chan *hsuc)
|
||||
|
||||
if (hsuc->direction == DMA_MEM_TO_DEV) {
|
||||
bsr = config->dst_maxburst;
|
||||
mtsr = config->dst_addr_width;
|
||||
mtsr = config->src_addr_width;
|
||||
} else if (hsuc->direction == DMA_DEV_TO_MEM) {
|
||||
bsr = config->src_maxburst;
|
||||
mtsr = config->src_addr_width;
|
||||
mtsr = config->dst_addr_width;
|
||||
}
|
||||
|
||||
hsu_chan_disable(hsuc);
|
||||
@ -135,7 +135,7 @@ static u32 hsu_dma_chan_get_sr(struct hsu_dma_chan *hsuc)
|
||||
sr = hsu_chan_readl(hsuc, HSU_CH_SR);
|
||||
spin_unlock_irqrestore(&hsuc->vchan.lock, flags);
|
||||
|
||||
return sr;
|
||||
return sr & ~(HSU_CH_SR_DESCE_ANY | HSU_CH_SR_CDESC_ANY);
|
||||
}
|
||||
|
||||
irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr)
|
||||
@ -254,10 +254,13 @@ static void hsu_dma_issue_pending(struct dma_chan *chan)
|
||||
static size_t hsu_dma_active_desc_size(struct hsu_dma_chan *hsuc)
|
||||
{
|
||||
struct hsu_dma_desc *desc = hsuc->desc;
|
||||
size_t bytes = desc->length;
|
||||
size_t bytes = 0;
|
||||
int i;
|
||||
|
||||
i = desc->active % HSU_DMA_CHAN_NR_DESC;
|
||||
for (i = desc->active; i < desc->nents; i++)
|
||||
bytes += desc->sg[i].len;
|
||||
|
||||
i = HSU_DMA_CHAN_NR_DESC - 1;
|
||||
do {
|
||||
bytes += hsu_chan_readl(hsuc, HSU_CH_DxTSR(i));
|
||||
} while (--i >= 0);
|
||||
|
@ -41,6 +41,9 @@
|
||||
#define HSU_CH_SR_DESCTO(x) BIT(8 + (x))
|
||||
#define HSU_CH_SR_DESCTO_ANY (BIT(11) | BIT(10) | BIT(9) | BIT(8))
|
||||
#define HSU_CH_SR_CHE BIT(15)
|
||||
#define HSU_CH_SR_DESCE(x) BIT(16 + (x))
|
||||
#define HSU_CH_SR_DESCE_ANY (BIT(19) | BIT(18) | BIT(17) | BIT(16))
|
||||
#define HSU_CH_SR_CDESC_ANY (BIT(31) | BIT(30))
|
||||
|
||||
/* Bits in HSU_CH_CR */
|
||||
#define HSU_CH_CR_CHA BIT(0)
|
||||
|
@ -48,6 +48,7 @@ struct omap_chan {
|
||||
unsigned dma_sig;
|
||||
bool cyclic;
|
||||
bool paused;
|
||||
bool running;
|
||||
|
||||
int dma_ch;
|
||||
struct omap_desc *desc;
|
||||
@ -294,6 +295,8 @@ static void omap_dma_start(struct omap_chan *c, struct omap_desc *d)
|
||||
|
||||
/* Enable channel */
|
||||
omap_dma_chan_write(c, CCR, d->ccr | CCR_ENABLE);
|
||||
|
||||
c->running = true;
|
||||
}
|
||||
|
||||
static void omap_dma_stop(struct omap_chan *c)
|
||||
@ -355,6 +358,8 @@ static void omap_dma_stop(struct omap_chan *c)
|
||||
|
||||
omap_dma_chan_write(c, CLNK_CTRL, val);
|
||||
}
|
||||
|
||||
c->running = false;
|
||||
}
|
||||
|
||||
static void omap_dma_start_sg(struct omap_chan *c, struct omap_desc *d,
|
||||
@ -673,15 +678,20 @@ static enum dma_status omap_dma_tx_status(struct dma_chan *chan,
|
||||
struct omap_chan *c = to_omap_dma_chan(chan);
|
||||
struct virt_dma_desc *vd;
|
||||
enum dma_status ret;
|
||||
uint32_t ccr;
|
||||
unsigned long flags;
|
||||
|
||||
ccr = omap_dma_chan_read(c, CCR);
|
||||
/* The channel is no longer active, handle the completion right away */
|
||||
if (!(ccr & CCR_ENABLE))
|
||||
omap_dma_callback(c->dma_ch, 0, c);
|
||||
|
||||
ret = dma_cookie_status(chan, cookie, txstate);
|
||||
|
||||
if (!c->paused && c->running) {
|
||||
uint32_t ccr = omap_dma_chan_read(c, CCR);
|
||||
/*
|
||||
* The channel is no longer active, set the return value
|
||||
* accordingly
|
||||
*/
|
||||
if (!(ccr & CCR_ENABLE))
|
||||
ret = DMA_COMPLETE;
|
||||
}
|
||||
|
||||
if (ret == DMA_COMPLETE || !txstate)
|
||||
return ret;
|
||||
|
||||
@ -945,9 +955,7 @@ static struct dma_async_tx_descriptor *omap_dma_prep_dma_memcpy(
|
||||
d->ccr = c->ccr;
|
||||
d->ccr |= CCR_DST_AMODE_POSTINC | CCR_SRC_AMODE_POSTINC;
|
||||
|
||||
d->cicr = CICR_DROP_IE;
|
||||
if (tx_flags & DMA_PREP_INTERRUPT)
|
||||
d->cicr |= CICR_FRAME_IE;
|
||||
d->cicr = CICR_DROP_IE | CICR_FRAME_IE;
|
||||
|
||||
d->csdp = data_type;
|
||||
|
||||
|
@ -1236,7 +1236,7 @@ static struct dma_chan *of_dma_xilinx_xlate(struct of_phandle_args *dma_spec,
|
||||
struct xilinx_vdma_device *xdev = ofdma->of_dma_data;
|
||||
int chan_id = dma_spec->args[0];
|
||||
|
||||
if (chan_id >= XILINX_VDMA_MAX_CHANS_PER_DEVICE)
|
||||
if (chan_id >= XILINX_VDMA_MAX_CHANS_PER_DEVICE || !xdev->chan[chan_id])
|
||||
return NULL;
|
||||
|
||||
return dma_get_slave_channel(&xdev->chan[chan_id]->common);
|
||||
|
Loading…
Reference in New Issue
Block a user