aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/dma/edma.c50
1 files changed, 49 insertions, 1 deletions
diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c
index 4c1c258a5b54..2966ef06c477 100644
--- a/drivers/dma/edma.c
+++ b/drivers/dma/edma.c
@@ -70,6 +70,7 @@ struct edma_chan {
70 int ch_num; 70 int ch_num;
71 bool alloced; 71 bool alloced;
72 int slot[EDMA_MAX_SLOTS]; 72 int slot[EDMA_MAX_SLOTS];
73 int missed;
73 struct dma_slave_config cfg; 74 struct dma_slave_config cfg;
74}; 75};
75 76
@@ -170,6 +171,20 @@ static void edma_execute(struct edma_chan *echan)
170 dev_dbg(dev, "first transfer starting %d\n", echan->ch_num); 171 dev_dbg(dev, "first transfer starting %d\n", echan->ch_num);
171 edma_start(echan->ch_num); 172 edma_start(echan->ch_num);
172 } 173 }
174
175 /*
176 * This happens due to setup times between intermediate transfers
177 * in long SG lists which have to be broken up into transfers of
178 * MAX_NR_SG
179 */
180 if (echan->missed) {
181 dev_dbg(dev, "missed event in execute detected\n");
182 edma_clean_channel(echan->ch_num);
183 edma_stop(echan->ch_num);
184 edma_start(echan->ch_num);
185 edma_trigger_channel(echan->ch_num);
186 echan->missed = 0;
187 }
173} 188}
174 189
175static int edma_terminate_all(struct edma_chan *echan) 190static int edma_terminate_all(struct edma_chan *echan)
@@ -387,6 +402,7 @@ static void edma_callback(unsigned ch_num, u16 ch_status, void *data)
387 struct device *dev = echan->vchan.chan.device->dev; 402 struct device *dev = echan->vchan.chan.device->dev;
388 struct edma_desc *edesc; 403 struct edma_desc *edesc;
389 unsigned long flags; 404 unsigned long flags;
405 struct edmacc_param p;
390 406
391 /* Pause the channel */ 407 /* Pause the channel */
392 edma_pause(echan->ch_num); 408 edma_pause(echan->ch_num);
@@ -412,7 +428,39 @@ static void edma_callback(unsigned ch_num, u16 ch_status, void *data)
412 428
413 break; 429 break;
414 case DMA_CC_ERROR: 430 case DMA_CC_ERROR:
415 dev_dbg(dev, "transfer error on channel %d\n", ch_num); 431 spin_lock_irqsave(&echan->vchan.lock, flags);
432
433 edma_read_slot(EDMA_CHAN_SLOT(echan->slot[0]), &p);
434
435 /*
436 * Issue later based on missed flag which will be sure
437 * to happen as:
438 * (1) we finished transmitting an intermediate slot and
439 * edma_execute is coming up.
440 * (2) or we finished current transfer and issue will
441 * call edma_execute.
442 *
443 * Important note: issuing can be dangerous here and
444 * lead to some nasty recursion when we are in a NULL
445 * slot. So we avoid doing so and set the missed flag.
446 */
447 if (p.a_b_cnt == 0 && p.ccnt == 0) {
448 dev_dbg(dev, "Error occurred, looks like slot is null, just setting miss\n");
449 echan->missed = 1;
450 } else {
451 /*
452 * The slot is already programmed but the event got
453 * missed, so its safe to issue it here.
454 */
455 dev_dbg(dev, "Error occurred but slot is non-null, TRIGGERING\n");
456 edma_clean_channel(echan->ch_num);
457 edma_stop(echan->ch_num);
458 edma_start(echan->ch_num);
459 edma_trigger_channel(echan->ch_num);
460 }
461
462 spin_unlock_irqrestore(&echan->vchan.lock, flags);
463
416 break; 464 break;
417 default: 465 default:
418 break; 466 break;