Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dma: i.MX31 IPU DMA robustness improvements

Add DMA error handling to the ISR, move common code fragments to functions, fix
scatter-gather element queuing in the ISR, survive channel freeing and
re-allocation in a quick succession.

Signed-off-by: Guennadi Liakhovetski <lg@denx.de>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>

authored by

Guennadi Liakhovetski and committed by
Dan Williams
8d47bae0 234f2df5

+181 -84
+181 -84
drivers/dma/ipu/ipu_idmac.c
··· 28 28 #define FS_VF_IN_VALID 0x00000002 29 29 #define FS_ENC_IN_VALID 0x00000001 30 30 31 + static int ipu_disable_channel(struct idmac *idmac, struct idmac_channel *ichan, 32 + bool wait_for_stop); 33 + 31 34 /* 32 35 * There can be only one, we could allocate it dynamically, but then we'd have 33 36 * to add an extra parameter to some functions, and use something as ugly as ··· 765 762 * function will fail if the buffer is set to ready. 766 763 */ 767 764 /* Called under spin_lock(_irqsave)(&ichan->lock) */ 768 - static int ipu_update_channel_buffer(enum ipu_channel channel, 765 + static int ipu_update_channel_buffer(struct idmac_channel *ichan, 769 766 int buffer_n, dma_addr_t phyaddr) 770 767 { 768 + enum ipu_channel channel = ichan->dma_chan.chan_id; 771 769 uint32_t reg; 772 770 unsigned long flags; 773 771 ··· 777 773 if (buffer_n == 0) { 778 774 reg = idmac_read_ipureg(&ipu_data, IPU_CHA_BUF0_RDY); 779 775 if (reg & (1UL << channel)) { 780 - spin_unlock_irqrestore(&ipu_data.lock, flags); 781 - return -EACCES; 776 + ipu_ic_disable_task(&ipu_data, channel); 777 + ichan->status = IPU_CHANNEL_READY; 782 778 } 783 779 784 780 /* 44.3.3.1.9 - Row Number 1 (WORD1, offset 0) */ ··· 788 784 } else { 789 785 reg = idmac_read_ipureg(&ipu_data, IPU_CHA_BUF1_RDY); 790 786 if (reg & (1UL << channel)) { 791 - spin_unlock_irqrestore(&ipu_data.lock, flags); 792 - return -EACCES; 787 + ipu_ic_disable_task(&ipu_data, channel); 788 + ichan->status = IPU_CHANNEL_READY; 793 789 } 794 790 795 791 /* Check if double-buffering is already enabled */ ··· 811 807 } 812 808 813 809 /* Called under spin_lock_irqsave(&ichan->lock) */ 810 + static int ipu_submit_buffer(struct idmac_channel *ichan, 811 + struct idmac_tx_desc *desc, struct scatterlist *sg, int buf_idx) 812 + { 813 + unsigned int chan_id = ichan->dma_chan.chan_id; 814 + struct device *dev = &ichan->dma_chan.dev->device; 815 + int ret; 816 + 817 + if (async_tx_test_ack(&desc->txd)) 818 + return -EINTR; 819 + 820 + /* 821 + * On first invocation this shouldn't be necessary, the call to 822 + * ipu_init_channel_buffer() above will set addresses for us, so we 823 + * could make it conditional on status >= IPU_CHANNEL_ENABLED, but 824 + * doing it again shouldn't hurt either. 825 + */ 826 + ret = ipu_update_channel_buffer(ichan, buf_idx, 827 + sg_dma_address(sg)); 828 + 829 + if (ret < 0) { 830 + dev_err(dev, "Updating sg %p on channel 0x%x buffer %d failed!\n", 831 + sg, chan_id, buf_idx); 832 + return ret; 833 + } 834 + 835 + ipu_select_buffer(chan_id, buf_idx); 836 + dev_dbg(dev, "Updated sg %p on channel 0x%x buffer %d\n", 837 + sg, chan_id, buf_idx); 838 + 839 + return 0; 840 + } 841 + 842 + /* Called under spin_lock_irqsave(&ichan->lock) */ 814 843 static int ipu_submit_channel_buffers(struct idmac_channel *ichan, 815 844 struct idmac_tx_desc *desc) 816 845 { ··· 854 817 if (!ichan->sg[i]) { 855 818 ichan->sg[i] = sg; 856 819 857 - /* 858 - * On first invocation this shouldn't be necessary, the 859 - * call to ipu_init_channel_buffer() above will set 860 - * addresses for us, so we could make it conditional 861 - * on status >= IPU_CHANNEL_ENABLED, but doing it again 862 - * shouldn't hurt either. 863 - */ 864 - ret = ipu_update_channel_buffer(ichan->dma_chan.chan_id, i, 865 - sg_dma_address(sg)); 820 + ret = ipu_submit_buffer(ichan, desc, sg, i); 866 821 if (ret < 0) 867 822 return ret; 868 - 869 - ipu_select_buffer(ichan->dma_chan.chan_id, i); 870 823 871 824 sg = sg_next(sg); 872 825 } ··· 871 844 struct idmac_channel *ichan = to_idmac_chan(tx->chan); 872 845 struct idmac *idmac = to_idmac(tx->chan->device); 873 846 struct ipu *ipu = to_ipu(idmac); 847 + struct device *dev = &ichan->dma_chan.dev->device; 874 848 dma_cookie_t cookie; 875 849 unsigned long flags; 850 + int ret; 876 851 877 852 /* Sanity check */ 878 853 if (!list_empty(&desc->list)) { 879 854 /* The descriptor doesn't belong to client */ 880 - dev_err(&ichan->dma_chan.dev->device, 881 - "Descriptor %p not prepared!\n", tx); 855 + dev_err(dev, "Descriptor %p not prepared!\n", tx); 882 856 return -EBUSY; 883 857 } 884 858 885 859 mutex_lock(&ichan->chan_mutex); 860 + 861 + async_tx_clear_ack(tx); 886 862 887 863 if (ichan->status < IPU_CHANNEL_READY) { 888 864 struct idmac_video_param *video = &ichan->params.video; ··· 910 880 goto out; 911 881 } 912 882 913 - /* ipu->lock can be taken under ichan->lock, but not v.v. */ 914 - spin_lock_irqsave(&ichan->lock, flags); 915 - 916 - /* submit_buffers() atomically verifies and fills empty sg slots */ 917 - cookie = ipu_submit_channel_buffers(ichan, desc); 918 - 919 - spin_unlock_irqrestore(&ichan->lock, flags); 920 - 921 - if (cookie < 0) 922 - goto out; 883 + dev_dbg(dev, "Submitting sg %p\n", &desc->sg[0]); 923 884 924 885 cookie = ichan->dma_chan.cookie; 925 886 ··· 920 899 /* from dmaengine.h: "last cookie value returned to client" */ 921 900 ichan->dma_chan.cookie = cookie; 922 901 tx->cookie = cookie; 902 + 903 + /* ipu->lock can be taken under ichan->lock, but not v.v. */ 923 904 spin_lock_irqsave(&ichan->lock, flags); 905 + 924 906 list_add_tail(&desc->list, &ichan->queue); 907 + /* submit_buffers() atomically verifies and fills empty sg slots */ 908 + ret = ipu_submit_channel_buffers(ichan, desc); 909 + 925 910 spin_unlock_irqrestore(&ichan->lock, flags); 926 911 912 + if (ret < 0) { 913 + cookie = ret; 914 + goto dequeue; 915 + } 916 + 927 917 if (ichan->status < IPU_CHANNEL_ENABLED) { 928 - int ret = ipu_enable_channel(idmac, ichan); 918 + ret = ipu_enable_channel(idmac, ichan); 929 919 if (ret < 0) { 930 920 cookie = ret; 931 - spin_lock_irqsave(&ichan->lock, flags); 932 - list_del_init(&desc->list); 933 - spin_unlock_irqrestore(&ichan->lock, flags); 934 - tx->cookie = cookie; 935 - ichan->dma_chan.cookie = cookie; 921 + goto dequeue; 936 922 } 937 923 } 938 924 939 925 dump_idmac_reg(ipu); 926 + 927 + dequeue: 928 + if (cookie < 0) { 929 + spin_lock_irqsave(&ichan->lock, flags); 930 + list_del_init(&desc->list); 931 + spin_unlock_irqrestore(&ichan->lock, flags); 932 + tx->cookie = cookie; 933 + ichan->dma_chan.cookie = cookie; 934 + } 940 935 941 936 out: 942 937 mutex_unlock(&ichan->chan_mutex); ··· 1200 1163 return 0; 1201 1164 } 1202 1165 1166 + static struct scatterlist *idmac_sg_next(struct idmac_channel *ichan, 1167 + struct idmac_tx_desc **desc, struct scatterlist *sg) 1168 + { 1169 + struct scatterlist *sgnew = sg ? sg_next(sg) : NULL; 1170 + 1171 + if (sgnew) 1172 + /* next sg-element in this list */ 1173 + return sgnew; 1174 + 1175 + if ((*desc)->list.next == &ichan->queue) 1176 + /* No more descriptors on the queue */ 1177 + return NULL; 1178 + 1179 + /* Fetch next descriptor */ 1180 + *desc = list_entry((*desc)->list.next, struct idmac_tx_desc, list); 1181 + return (*desc)->sg; 1182 + } 1183 + 1203 1184 /* 1204 1185 * We have several possibilities here: 1205 1186 * current BUF next BUF ··· 1233 1178 static irqreturn_t idmac_interrupt(int irq, void *dev_id) 1234 1179 { 1235 1180 struct idmac_channel *ichan = dev_id; 1181 + struct device *dev = &ichan->dma_chan.dev->device; 1236 1182 unsigned int chan_id = ichan->dma_chan.chan_id; 1237 1183 struct scatterlist **sg, *sgnext, *sgnew = NULL; 1238 1184 /* Next transfer descriptor */ 1239 - struct idmac_tx_desc *desc = NULL, *descnew; 1185 + struct idmac_tx_desc *desc, *descnew; 1240 1186 dma_async_tx_callback callback; 1241 1187 void *callback_param; 1242 1188 bool done = false; 1243 - u32 ready0 = idmac_read_ipureg(&ipu_data, IPU_CHA_BUF0_RDY), 1244 - ready1 = idmac_read_ipureg(&ipu_data, IPU_CHA_BUF1_RDY), 1245 - curbuf = idmac_read_ipureg(&ipu_data, IPU_CHA_CUR_BUF); 1189 + u32 ready0, ready1, curbuf, err; 1190 + unsigned long flags; 1246 1191 1247 1192 /* IDMAC has cleared the respective BUFx_RDY bit, we manage the buffer */ 1248 1193 1249 - pr_debug("IDMAC irq %d\n", irq); 1194 + dev_dbg(dev, "IDMAC irq %d, buf %d\n", irq, ichan->active_buffer); 1195 + 1196 + spin_lock_irqsave(&ipu_data.lock, flags); 1197 + 1198 + ready0 = idmac_read_ipureg(&ipu_data, IPU_CHA_BUF0_RDY); 1199 + ready1 = idmac_read_ipureg(&ipu_data, IPU_CHA_BUF1_RDY); 1200 + curbuf = idmac_read_ipureg(&ipu_data, IPU_CHA_CUR_BUF); 1201 + err = idmac_read_ipureg(&ipu_data, IPU_INT_STAT_4); 1202 + 1203 + if (err & (1 << chan_id)) { 1204 + idmac_write_ipureg(&ipu_data, 1 << chan_id, IPU_INT_STAT_4); 1205 + spin_unlock_irqrestore(&ipu_data.lock, flags); 1206 + /* 1207 + * Doing this 1208 + * ichan->sg[0] = ichan->sg[1] = NULL; 1209 + * you can force channel re-enable on the next tx_submit(), but 1210 + * this is dirty - think about descriptors with multiple 1211 + * sg elements. 1212 + */ 1213 + dev_warn(dev, "NFB4EOF on channel %d, ready %x, %x, cur %x\n", 1214 + chan_id, ready0, ready1, curbuf); 1215 + return IRQ_HANDLED; 1216 + } 1217 + spin_unlock_irqrestore(&ipu_data.lock, flags); 1218 + 1250 1219 /* Other interrupts do not interfere with this channel */ 1251 1220 spin_lock(&ichan->lock); 1252 - 1253 1221 if (unlikely(chan_id != IDMAC_SDC_0 && chan_id != IDMAC_SDC_1 && 1254 1222 ((curbuf >> chan_id) & 1) == ichan->active_buffer)) { 1255 1223 int i = 100; ··· 1287 1209 1288 1210 if (!i) { 1289 1211 spin_unlock(&ichan->lock); 1290 - dev_dbg(ichan->dma_chan.device->dev, 1212 + dev_dbg(dev, 1291 1213 "IRQ on active buffer on channel %x, active " 1292 1214 "%d, ready %x, %x, current %x!\n", chan_id, 1293 1215 ichan->active_buffer, ready0, ready1, curbuf); 1294 1216 return IRQ_NONE; 1295 - } 1217 + } else 1218 + dev_dbg(dev, 1219 + "Buffer deactivated on channel %x, active " 1220 + "%d, ready %x, %x, current %x, rest %d!\n", chan_id, 1221 + ichan->active_buffer, ready0, ready1, curbuf, i); 1296 1222 } 1297 1223 1298 1224 if (unlikely((ichan->active_buffer && (ready1 >> chan_id) & 1) || 1299 1225 (!ichan->active_buffer && (ready0 >> chan_id) & 1) 1300 1226 )) { 1301 1227 spin_unlock(&ichan->lock); 1302 - dev_dbg(ichan->dma_chan.device->dev, 1228 + dev_dbg(dev, 1303 1229 "IRQ with active buffer still ready on channel %x, " 1304 1230 "active %d, ready %x, %x!\n", chan_id, 1305 1231 ichan->active_buffer, ready0, ready1); ··· 1311 1229 } 1312 1230 1313 1231 if (unlikely(list_empty(&ichan->queue))) { 1232 + ichan->sg[ichan->active_buffer] = NULL; 1314 1233 spin_unlock(&ichan->lock); 1315 - dev_err(ichan->dma_chan.device->dev, 1234 + dev_err(dev, 1316 1235 "IRQ without queued buffers on channel %x, active %d, " 1317 1236 "ready %x, %x!\n", chan_id, 1318 1237 ichan->active_buffer, ready0, ready1); ··· 1328 1245 sg = &ichan->sg[ichan->active_buffer]; 1329 1246 sgnext = ichan->sg[!ichan->active_buffer]; 1330 1247 1248 + if (!*sg) { 1249 + spin_unlock(&ichan->lock); 1250 + return IRQ_HANDLED; 1251 + } 1252 + 1253 + desc = list_entry(ichan->queue.next, struct idmac_tx_desc, list); 1254 + descnew = desc; 1255 + 1256 + dev_dbg(dev, "IDMAC irq %d, dma 0x%08x, next dma 0x%08x, current %d, curbuf 0x%08x\n", 1257 + irq, sg_dma_address(*sg), sgnext ? sg_dma_address(sgnext) : 0, ichan->active_buffer, curbuf); 1258 + 1259 + /* Find the descriptor of sgnext */ 1260 + sgnew = idmac_sg_next(ichan, &descnew, *sg); 1261 + if (sgnext != sgnew) 1262 + dev_err(dev, "Submitted buffer %p, next buffer %p\n", sgnext, sgnew); 1263 + 1331 1264 /* 1332 1265 * if sgnext == NULL sg must be the last element in a scatterlist and 1333 1266 * queue must be empty 1334 1267 */ 1335 1268 if (unlikely(!sgnext)) { 1336 - if (unlikely(sg_next(*sg))) { 1337 - dev_err(ichan->dma_chan.device->dev, 1338 - "Broken buffer-update locking on channel %x!\n", 1339 - chan_id); 1340 - /* We'll let the user catch up */ 1269 + if (!WARN_ON(sg_next(*sg))) 1270 + dev_dbg(dev, "Underrun on channel %x\n", chan_id); 1271 + ichan->sg[!ichan->active_buffer] = sgnew; 1272 + 1273 + if (unlikely(sgnew)) { 1274 + ipu_submit_buffer(ichan, descnew, sgnew, !ichan->active_buffer); 1341 1275 } else { 1342 - /* Underrun */ 1276 + spin_lock_irqsave(&ipu_data.lock, flags); 1343 1277 ipu_ic_disable_task(&ipu_data, chan_id); 1344 - dev_dbg(ichan->dma_chan.device->dev, 1345 - "Underrun on channel %x\n", chan_id); 1278 + spin_unlock_irqrestore(&ipu_data.lock, flags); 1346 1279 ichan->status = IPU_CHANNEL_READY; 1347 1280 /* Continue to check for complete descriptor */ 1348 1281 } 1349 1282 } 1350 1283 1351 - desc = list_entry(ichan->queue.next, struct idmac_tx_desc, list); 1352 - 1353 - /* First calculate and submit the next sg element */ 1354 - if (likely(sgnext)) 1355 - sgnew = sg_next(sgnext); 1356 - 1357 - if (unlikely(!sgnew)) { 1358 - /* Start a new scatterlist, if any queued */ 1359 - if (likely(desc->list.next != &ichan->queue)) { 1360 - descnew = list_entry(desc->list.next, 1361 - struct idmac_tx_desc, list); 1362 - sgnew = &descnew->sg[0]; 1363 - } 1364 - } 1284 + /* Calculate and submit the next sg element */ 1285 + sgnew = idmac_sg_next(ichan, &descnew, sgnew); 1365 1286 1366 1287 if (unlikely(!sg_next(*sg)) || !sgnext) { 1367 1288 /* ··· 1378 1291 1379 1292 *sg = sgnew; 1380 1293 1381 - if (likely(sgnew)) { 1382 - int ret; 1383 - 1384 - ret = ipu_update_channel_buffer(chan_id, ichan->active_buffer, 1385 - sg_dma_address(*sg)); 1386 - if (ret < 0) 1387 - dev_err(ichan->dma_chan.device->dev, 1388 - "Failed to update buffer on channel %x buffer %d!\n", 1389 - chan_id, ichan->active_buffer); 1390 - else 1391 - ipu_select_buffer(chan_id, ichan->active_buffer); 1294 + if (likely(sgnew) && 1295 + ipu_submit_buffer(ichan, descnew, sgnew, ichan->active_buffer) < 0) { 1296 + callback = desc->txd.callback; 1297 + callback_param = desc->txd.callback_param; 1298 + spin_unlock(&ichan->lock); 1299 + callback(callback_param); 1300 + spin_lock(&ichan->lock); 1392 1301 } 1393 1302 1394 1303 /* Flip the active buffer - even if update above failed */ ··· 1412 1329 struct idmac_channel *ichan = ipu->channel + i; 1413 1330 struct idmac_tx_desc *desc; 1414 1331 unsigned long flags; 1415 - int j; 1332 + struct scatterlist *sg; 1333 + int j, k; 1416 1334 1417 1335 for (j = 0; j < ichan->n_tx_desc; j++) { 1418 1336 desc = ichan->desc + j; 1419 1337 spin_lock_irqsave(&ichan->lock, flags); 1420 1338 if (async_tx_test_ack(&desc->txd)) { 1421 1339 list_move(&desc->list, &ichan->free_list); 1340 + for_each_sg(desc->sg, sg, desc->sg_len, k) { 1341 + if (ichan->sg[0] == sg) 1342 + ichan->sg[0] = NULL; 1343 + else if (ichan->sg[1] == sg) 1344 + ichan->sg[1] = NULL; 1345 + } 1422 1346 async_tx_clear_ack(&desc->txd); 1423 1347 } 1424 1348 spin_unlock_irqrestore(&ichan->lock, flags); ··· 1561 1471 goto eimap; 1562 1472 1563 1473 ichan->eof_irq = ret; 1564 - ret = request_irq(ichan->eof_irq, idmac_interrupt, 0, 1565 - ichan->eof_name, ichan); 1566 - if (ret < 0) 1567 - goto erirq; 1474 + 1475 + /* 1476 + * Important to first disable the channel, because maybe someone 1477 + * used it before us, e.g., the bootloader 1478 + */ 1479 + ipu_disable_channel(idmac, ichan, true); 1568 1480 1569 1481 ret = ipu_init_channel(idmac, ichan); 1570 1482 if (ret < 0) 1571 1483 goto eichan; 1484 + 1485 + ret = request_irq(ichan->eof_irq, idmac_interrupt, 0, 1486 + ichan->eof_name, ichan); 1487 + if (ret < 0) 1488 + goto erirq; 1572 1489 1573 1490 ichan->status = IPU_CHANNEL_INITIALIZED; 1574 1491 ··· 1584 1487 1585 1488 return ret; 1586 1489 1587 - eichan: 1588 - free_irq(ichan->eof_irq, ichan); 1589 1490 erirq: 1491 + ipu_uninit_channel(idmac, ichan); 1492 + eichan: 1590 1493 ipu_irq_unmap(ichan->dma_chan.chan_id); 1591 1494 eimap: 1592 1495 return ret;