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); |
