diff options
-rw-r--r-- | Documentation/powerpc/dts-bindings/fsl/dma.txt | 8 | ||||
-rw-r--r-- | drivers/dma/fsldma.c | 173 |
2 files changed, 137 insertions, 44 deletions
diff --git a/Documentation/powerpc/dts-bindings/fsl/dma.txt b/Documentation/powerpc/dts-bindings/fsl/dma.txt index 0732cdd05ba1..2a4b4bce6110 100644 --- a/Documentation/powerpc/dts-bindings/fsl/dma.txt +++ b/Documentation/powerpc/dts-bindings/fsl/dma.txt | |||
@@ -44,21 +44,29 @@ Example: | |||
44 | compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel"; | 44 | compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel"; |
45 | cell-index = <0>; | 45 | cell-index = <0>; |
46 | reg = <0 0x80>; | 46 | reg = <0 0x80>; |
47 | interrupt-parent = <&ipic>; | ||
48 | interrupts = <71 8>; | ||
47 | }; | 49 | }; |
48 | dma-channel@80 { | 50 | dma-channel@80 { |
49 | compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel"; | 51 | compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel"; |
50 | cell-index = <1>; | 52 | cell-index = <1>; |
51 | reg = <0x80 0x80>; | 53 | reg = <0x80 0x80>; |
54 | interrupt-parent = <&ipic>; | ||
55 | interrupts = <71 8>; | ||
52 | }; | 56 | }; |
53 | dma-channel@100 { | 57 | dma-channel@100 { |
54 | compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel"; | 58 | compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel"; |
55 | cell-index = <2>; | 59 | cell-index = <2>; |
56 | reg = <0x100 0x80>; | 60 | reg = <0x100 0x80>; |
61 | interrupt-parent = <&ipic>; | ||
62 | interrupts = <71 8>; | ||
57 | }; | 63 | }; |
58 | dma-channel@180 { | 64 | dma-channel@180 { |
59 | compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel"; | 65 | compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel"; |
60 | cell-index = <3>; | 66 | cell-index = <3>; |
61 | reg = <0x180 0x80>; | 67 | reg = <0x180 0x80>; |
68 | interrupt-parent = <&ipic>; | ||
69 | interrupts = <71 8>; | ||
62 | }; | 70 | }; |
63 | }; | 71 | }; |
64 | 72 | ||
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 | |||
970 | static irqreturn_t fsldma_chan_irq(int irq, void *data) | 974 | static 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 | ||
1051 | static irqreturn_t fsldma_irq(int irq, void *data) | 1055 | static 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 | |||
1061 | static 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 | ||
1065 | static void dma_do_tasklet(unsigned long data) | 1092 | static 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 | |||
1112 | static 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 | |||
1152 | out_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 | ||
1166 | out_list_del: | ||
1167 | irq_dispose_mapping(fchan->irq); | ||
1168 | list_del_init(&fchan->common.device_node); | ||
1169 | out_iounmap_regs: | 1254 | out_iounmap_regs: |
1170 | iounmap(fchan->regs); | 1255 | iounmap(fchan->regs); |
1171 | out_free_fchan: | 1256 | out_free_fchan: |
@@ -1176,11 +1261,7 @@ out_return: | |||
1176 | 1261 | ||
1177 | static void fsl_dma_chan_remove(struct fsldma_chan *fchan) | 1262 | static 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 | ||
1261 | out_iounmap_regs: | ||
1262 | iounmap(fdev->regs); | ||
1263 | out_free_fdev: | 1348 | out_free_fdev: |
1349 | irq_dispose_mapping(fdev->irq); | ||
1264 | kfree(fdev); | 1350 | kfree(fdev); |
1265 | out_return: | 1351 | out_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); |