aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/fsldma.c
diff options
context:
space:
mode:
authorIra Snyder <iws@ovro.caltech.edu>2010-01-06 08:34:04 -0500
committerDan Williams <dan.j.williams@intel.com>2010-02-02 16:51:41 -0500
commitd3f620b2c4fecdc8e060b70e8d92d29fc01c6126 (patch)
tree652ddf41247241ef3f82419a80e36bb5ee5dd810 /drivers/dma/fsldma.c
parente7a29151de1bd52081f27f149b68074fac0323be (diff)
fsldma: simplify IRQ probing and handling
The IRQ probing is needlessly complex. All off the 83xx device trees in arch/powerpc/boot/dts/ specify 5 interrupts per DMA controller: one for the controller, and one for each channel. These interrupts are all attached to the same IRQ line. This causes an interesting situation if two channels interrupt at the same time. The per-controller handler will handle the first channel, and the per-channel handler will handle the remaining channels. Instead of this mess, we fix the bug in the per-controller handler, and make it handle all channels that generated an interrupt. When a per-controller handler is specified in the device tree, we prefer to use the shared handler instead of the per-channel handler. The 85xx/86xx controllers do not have a per-controller interrupt, and instead use a per-channel interrupt. This behavior has not been changed. Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/dma/fsldma.c')
-rw-r--r--drivers/dma/fsldma.c173
1 files changed, 129 insertions, 44 deletions
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 507b29716bbd..6a905929ef01 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -967,6 +967,10 @@ static enum dma_status fsl_dma_is_complete(struct dma_chan *chan,
967 return dma_async_is_complete(cookie, last_complete, last_used); 967 return dma_async_is_complete(cookie, last_complete, last_used);
968} 968}
969 969
970/*----------------------------------------------------------------------------*/
971/* Interrupt Handling */
972/*----------------------------------------------------------------------------*/
973
970static irqreturn_t fsldma_chan_irq(int irq, void *data) 974static irqreturn_t fsldma_chan_irq(int irq, void *data)
971{ 975{
972 struct fsldma_chan *fsl_chan = data; 976 struct fsldma_chan *fsl_chan = data;
@@ -1048,24 +1052,116 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
1048 return IRQ_HANDLED; 1052 return IRQ_HANDLED;
1049} 1053}
1050 1054
1051static irqreturn_t fsldma_irq(int irq, void *data) 1055static void dma_do_tasklet(unsigned long data)
1056{
1057 struct fsldma_chan *fsl_chan = (struct fsldma_chan *)data;
1058 fsl_chan_ld_cleanup(fsl_chan);
1059}
1060
1061static irqreturn_t fsldma_ctrl_irq(int irq, void *data)
1052{ 1062{
1053 struct fsldma_device *fdev = data; 1063 struct fsldma_device *fdev = data;
1054 int ch_nr; 1064 struct fsldma_chan *chan;
1055 u32 gsr; 1065 unsigned int handled = 0;
1066 u32 gsr, mask;
1067 int i;
1056 1068
1057 gsr = (fdev->feature & FSL_DMA_BIG_ENDIAN) ? in_be32(fdev->regs) 1069 gsr = (fdev->feature & FSL_DMA_BIG_ENDIAN) ? in_be32(fdev->regs)
1058 : in_le32(fdev->regs); 1070 : in_le32(fdev->regs);
1059 ch_nr = (32 - ffs(gsr)) / 8; 1071 mask = 0xff000000;
1072 dev_dbg(fdev->dev, "IRQ: gsr 0x%.8x\n", gsr);
1060 1073
1061 return fdev->chan[ch_nr] ? fsldma_chan_irq(irq, 1074 for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) {
1062 fdev->chan[ch_nr]) : IRQ_NONE; 1075 chan = fdev->chan[i];
1076 if (!chan)
1077 continue;
1078
1079 if (gsr & mask) {
1080 dev_dbg(fdev->dev, "IRQ: chan %d\n", chan->id);
1081 fsldma_chan_irq(irq, chan);
1082 handled++;
1083 }
1084
1085 gsr &= ~mask;
1086 mask >>= 8;
1087 }
1088
1089 return IRQ_RETVAL(handled);
1063} 1090}
1064 1091
1065static void dma_do_tasklet(unsigned long data) 1092static void fsldma_free_irqs(struct fsldma_device *fdev)
1066{ 1093{
1067 struct fsldma_chan *fsl_chan = (struct fsldma_chan *)data; 1094 struct fsldma_chan *chan;
1068 fsl_chan_ld_cleanup(fsl_chan); 1095 int i;
1096
1097 if (fdev->irq != NO_IRQ) {
1098 dev_dbg(fdev->dev, "free per-controller IRQ\n");
1099 free_irq(fdev->irq, fdev);
1100 return;
1101 }
1102
1103 for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) {
1104 chan = fdev->chan[i];
1105 if (chan && chan->irq != NO_IRQ) {
1106 dev_dbg(fdev->dev, "free channel %d IRQ\n", chan->id);
1107 free_irq(chan->irq, chan);
1108 }
1109 }
1110}
1111
1112static int fsldma_request_irqs(struct fsldma_device *fdev)
1113{
1114 struct fsldma_chan *chan;
1115 int ret;
1116 int i;
1117
1118 /* if we have a per-controller IRQ, use that */
1119 if (fdev->irq != NO_IRQ) {
1120 dev_dbg(fdev->dev, "request per-controller IRQ\n");
1121 ret = request_irq(fdev->irq, fsldma_ctrl_irq, IRQF_SHARED,
1122 "fsldma-controller", fdev);
1123 return ret;
1124 }
1125
1126 /* no per-controller IRQ, use the per-channel IRQs */
1127 for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) {
1128 chan = fdev->chan[i];
1129 if (!chan)
1130 continue;
1131
1132 if (chan->irq == NO_IRQ) {
1133 dev_err(fdev->dev, "no interrupts property defined for "
1134 "DMA channel %d. Please fix your "
1135 "device tree\n", chan->id);
1136 ret = -ENODEV;
1137 goto out_unwind;
1138 }
1139
1140 dev_dbg(fdev->dev, "request channel %d IRQ\n", chan->id);
1141 ret = request_irq(chan->irq, fsldma_chan_irq, IRQF_SHARED,
1142 "fsldma-chan", chan);
1143 if (ret) {
1144 dev_err(fdev->dev, "unable to request IRQ for DMA "
1145 "channel %d\n", chan->id);
1146 goto out_unwind;
1147 }
1148 }
1149
1150 return 0;
1151
1152out_unwind:
1153 for (/* none */; i >= 0; i--) {
1154 chan = fdev->chan[i];
1155 if (!chan)
1156 continue;
1157
1158 if (chan->irq == NO_IRQ)
1159 continue;
1160
1161 free_irq(chan->irq, chan);
1162 }
1163
1164 return ret;
1069} 1165}
1070 1166
1071/*----------------------------------------------------------------------------*/ 1167/*----------------------------------------------------------------------------*/
@@ -1143,29 +1239,18 @@ static int __devinit fsl_dma_chan_probe(struct fsldma_device *fdev,
1143 1239
1144 fchan->common.device = &fdev->common; 1240 fchan->common.device = &fdev->common;
1145 1241
1242 /* find the IRQ line, if it exists in the device tree */
1243 fchan->irq = irq_of_parse_and_map(node, 0);
1244
1146 /* Add the channel to DMA device channel list */ 1245 /* Add the channel to DMA device channel list */
1147 list_add_tail(&fchan->common.device_node, &fdev->common.channels); 1246 list_add_tail(&fchan->common.device_node, &fdev->common.channels);
1148 fdev->common.chancnt++; 1247 fdev->common.chancnt++;
1149 1248
1150 fchan->irq = irq_of_parse_and_map(node, 0);
1151 if (fchan->irq != NO_IRQ) {
1152 err = request_irq(fchan->irq, &fsldma_chan_irq,
1153 IRQF_SHARED, "fsldma-channel", fchan);
1154 if (err) {
1155 dev_err(fdev->dev, "unable to request IRQ "
1156 "for channel %d\n", fchan->id);
1157 goto out_list_del;
1158 }
1159 }
1160
1161 dev_info(fdev->dev, "#%d (%s), irq %d\n", fchan->id, compatible, 1249 dev_info(fdev->dev, "#%d (%s), irq %d\n", fchan->id, compatible,
1162 fchan->irq != NO_IRQ ? fchan->irq : fdev->irq); 1250 fchan->irq != NO_IRQ ? fchan->irq : fdev->irq);
1163 1251
1164 return 0; 1252 return 0;
1165 1253
1166out_list_del:
1167 irq_dispose_mapping(fchan->irq);
1168 list_del_init(&fchan->common.device_node);
1169out_iounmap_regs: 1254out_iounmap_regs:
1170 iounmap(fchan->regs); 1255 iounmap(fchan->regs);
1171out_free_fchan: 1256out_free_fchan:
@@ -1176,11 +1261,7 @@ out_return:
1176 1261
1177static void fsl_dma_chan_remove(struct fsldma_chan *fchan) 1262static void fsl_dma_chan_remove(struct fsldma_chan *fchan)
1178{ 1263{
1179 if (fchan->irq != NO_IRQ) { 1264 irq_dispose_mapping(fchan->irq);
1180 free_irq(fchan->irq, fchan);
1181 irq_dispose_mapping(fchan->irq);
1182 }
1183
1184 list_del(&fchan->common.device_node); 1265 list_del(&fchan->common.device_node);
1185 iounmap(fchan->regs); 1266 iounmap(fchan->regs);
1186 kfree(fchan); 1267 kfree(fchan);
@@ -1211,6 +1292,9 @@ static int __devinit fsldma_of_probe(struct of_device *op,
1211 goto out_free_fdev; 1292 goto out_free_fdev;
1212 } 1293 }
1213 1294
1295 /* map the channel IRQ if it exists, but don't hookup the handler yet */
1296 fdev->irq = irq_of_parse_and_map(op->node, 0);
1297
1214 dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask); 1298 dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask);
1215 dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask); 1299 dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask);
1216 dma_cap_set(DMA_SLAVE, fdev->common.cap_mask); 1300 dma_cap_set(DMA_SLAVE, fdev->common.cap_mask);
@@ -1224,16 +1308,6 @@ static int __devinit fsldma_of_probe(struct of_device *op,
1224 fdev->common.device_terminate_all = fsl_dma_device_terminate_all; 1308 fdev->common.device_terminate_all = fsl_dma_device_terminate_all;
1225 fdev->common.dev = &op->dev; 1309 fdev->common.dev = &op->dev;
1226 1310
1227 fdev->irq = irq_of_parse_and_map(op->node, 0);
1228 if (fdev->irq != NO_IRQ) {
1229 err = request_irq(fdev->irq, &fsldma_irq, IRQF_SHARED,
1230 "fsldma-device", fdev);
1231 if (err) {
1232 dev_err(&op->dev, "unable to request IRQ\n");
1233 goto out_iounmap_regs;
1234 }
1235 }
1236
1237 dev_set_drvdata(&op->dev, fdev); 1311 dev_set_drvdata(&op->dev, fdev);
1238 1312
1239 /* 1313 /*
@@ -1255,12 +1329,24 @@ static int __devinit fsldma_of_probe(struct of_device *op,
1255 } 1329 }
1256 } 1330 }
1257 1331
1332 /*
1333 * Hookup the IRQ handler(s)
1334 *
1335 * If we have a per-controller interrupt, we prefer that to the
1336 * per-channel interrupts to reduce the number of shared interrupt
1337 * handlers on the same IRQ line
1338 */
1339 err = fsldma_request_irqs(fdev);
1340 if (err) {
1341 dev_err(fdev->dev, "unable to request IRQs\n");
1342 goto out_free_fdev;
1343 }
1344
1258 dma_async_device_register(&fdev->common); 1345 dma_async_device_register(&fdev->common);
1259 return 0; 1346 return 0;
1260 1347
1261out_iounmap_regs:
1262 iounmap(fdev->regs);
1263out_free_fdev: 1348out_free_fdev:
1349 irq_dispose_mapping(fdev->irq);
1264 kfree(fdev); 1350 kfree(fdev);
1265out_return: 1351out_return:
1266 return err; 1352 return err;
@@ -1274,14 +1360,13 @@ static int fsldma_of_remove(struct of_device *op)
1274 fdev = dev_get_drvdata(&op->dev); 1360 fdev = dev_get_drvdata(&op->dev);
1275 dma_async_device_unregister(&fdev->common); 1361 dma_async_device_unregister(&fdev->common);
1276 1362
1363 fsldma_free_irqs(fdev);
1364
1277 for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) { 1365 for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) {
1278 if (fdev->chan[i]) 1366 if (fdev->chan[i])
1279 fsl_dma_chan_remove(fdev->chan[i]); 1367 fsl_dma_chan_remove(fdev->chan[i]);
1280 } 1368 }
1281 1369
1282 if (fdev->irq != NO_IRQ)
1283 free_irq(fdev->irq, fdev);
1284
1285 iounmap(fdev->regs); 1370 iounmap(fdev->regs);
1286 dev_set_drvdata(&op->dev, NULL); 1371 dev_set_drvdata(&op->dev, NULL);
1287 kfree(fdev); 1372 kfree(fdev);