diff options
author | Dan Williams <dan.j.williams@intel.com> | 2009-09-08 20:53:57 -0400 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2009-09-08 20:53:57 -0400 |
commit | 3e48e656903e9fd8bc805c6a2c4264d7808d315b (patch) | |
tree | dfee34eb1f317b35f33a02291e65ce6ec46e3a5a /drivers/dma/iop-adma.c | |
parent | a6417dd58d6832f123f36c6f22c63ec1ab62ce1c (diff) | |
parent | f6dbf651615900646fe0ba1ef5ce1027e5b4748d (diff) |
Merge branch 'iop-raid6' into async-tx-next
Diffstat (limited to 'drivers/dma/iop-adma.c')
-rw-r--r-- | drivers/dma/iop-adma.c | 437 |
1 files changed, 393 insertions, 44 deletions
diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c index cecb6d657d55..518f557ef857 100644 --- a/drivers/dma/iop-adma.c +++ b/drivers/dma/iop-adma.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/platform_device.h> | 31 | #include <linux/platform_device.h> |
32 | #include <linux/memory.h> | 32 | #include <linux/memory.h> |
33 | #include <linux/ioport.h> | 33 | #include <linux/ioport.h> |
34 | #include <linux/raid/pq.h> | ||
34 | 35 | ||
35 | #include <mach/adma.h> | 36 | #include <mach/adma.h> |
36 | 37 | ||
@@ -57,65 +58,110 @@ static void iop_adma_free_slots(struct iop_adma_desc_slot *slot) | |||
57 | } | 58 | } |
58 | } | 59 | } |
59 | 60 | ||
61 | static void | ||
62 | iop_desc_unmap(struct iop_adma_chan *iop_chan, struct iop_adma_desc_slot *desc) | ||
63 | { | ||
64 | struct dma_async_tx_descriptor *tx = &desc->async_tx; | ||
65 | struct iop_adma_desc_slot *unmap = desc->group_head; | ||
66 | struct device *dev = &iop_chan->device->pdev->dev; | ||
67 | u32 len = unmap->unmap_len; | ||
68 | enum dma_ctrl_flags flags = tx->flags; | ||
69 | u32 src_cnt; | ||
70 | dma_addr_t addr; | ||
71 | dma_addr_t dest; | ||
72 | |||
73 | src_cnt = unmap->unmap_src_cnt; | ||
74 | dest = iop_desc_get_dest_addr(unmap, iop_chan); | ||
75 | if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP)) { | ||
76 | enum dma_data_direction dir; | ||
77 | |||
78 | if (src_cnt > 1) /* is xor? */ | ||
79 | dir = DMA_BIDIRECTIONAL; | ||
80 | else | ||
81 | dir = DMA_FROM_DEVICE; | ||
82 | |||
83 | dma_unmap_page(dev, dest, len, dir); | ||
84 | } | ||
85 | |||
86 | if (!(flags & DMA_COMPL_SKIP_SRC_UNMAP)) { | ||
87 | while (src_cnt--) { | ||
88 | addr = iop_desc_get_src_addr(unmap, iop_chan, src_cnt); | ||
89 | if (addr == dest) | ||
90 | continue; | ||
91 | dma_unmap_page(dev, addr, len, DMA_TO_DEVICE); | ||
92 | } | ||
93 | } | ||
94 | desc->group_head = NULL; | ||
95 | } | ||
96 | |||
97 | static void | ||
98 | iop_desc_unmap_pq(struct iop_adma_chan *iop_chan, struct iop_adma_desc_slot *desc) | ||
99 | { | ||
100 | struct dma_async_tx_descriptor *tx = &desc->async_tx; | ||
101 | struct iop_adma_desc_slot *unmap = desc->group_head; | ||
102 | struct device *dev = &iop_chan->device->pdev->dev; | ||
103 | u32 len = unmap->unmap_len; | ||
104 | enum dma_ctrl_flags flags = tx->flags; | ||
105 | u32 src_cnt = unmap->unmap_src_cnt; | ||
106 | dma_addr_t pdest = iop_desc_get_dest_addr(unmap, iop_chan); | ||
107 | dma_addr_t qdest = iop_desc_get_qdest_addr(unmap, iop_chan); | ||
108 | int i; | ||
109 | |||
110 | if (tx->flags & DMA_PREP_CONTINUE) | ||
111 | src_cnt -= 3; | ||
112 | |||
113 | if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP) && !desc->pq_check_result) { | ||
114 | dma_unmap_page(dev, pdest, len, DMA_BIDIRECTIONAL); | ||
115 | dma_unmap_page(dev, qdest, len, DMA_BIDIRECTIONAL); | ||
116 | } | ||
117 | |||
118 | if (!(flags & DMA_COMPL_SKIP_SRC_UNMAP)) { | ||
119 | dma_addr_t addr; | ||
120 | |||
121 | for (i = 0; i < src_cnt; i++) { | ||
122 | addr = iop_desc_get_src_addr(unmap, iop_chan, i); | ||
123 | dma_unmap_page(dev, addr, len, DMA_TO_DEVICE); | ||
124 | } | ||
125 | if (desc->pq_check_result) { | ||
126 | dma_unmap_page(dev, pdest, len, DMA_TO_DEVICE); | ||
127 | dma_unmap_page(dev, qdest, len, DMA_TO_DEVICE); | ||
128 | } | ||
129 | } | ||
130 | |||
131 | desc->group_head = NULL; | ||
132 | } | ||
133 | |||
134 | |||
60 | static dma_cookie_t | 135 | static dma_cookie_t |
61 | iop_adma_run_tx_complete_actions(struct iop_adma_desc_slot *desc, | 136 | iop_adma_run_tx_complete_actions(struct iop_adma_desc_slot *desc, |
62 | struct iop_adma_chan *iop_chan, dma_cookie_t cookie) | 137 | struct iop_adma_chan *iop_chan, dma_cookie_t cookie) |
63 | { | 138 | { |
64 | BUG_ON(desc->async_tx.cookie < 0); | 139 | struct dma_async_tx_descriptor *tx = &desc->async_tx; |
65 | if (desc->async_tx.cookie > 0) { | 140 | |
66 | cookie = desc->async_tx.cookie; | 141 | BUG_ON(tx->cookie < 0); |
67 | desc->async_tx.cookie = 0; | 142 | if (tx->cookie > 0) { |
143 | cookie = tx->cookie; | ||
144 | tx->cookie = 0; | ||
68 | 145 | ||
69 | /* call the callback (must not sleep or submit new | 146 | /* call the callback (must not sleep or submit new |
70 | * operations to this channel) | 147 | * operations to this channel) |
71 | */ | 148 | */ |
72 | if (desc->async_tx.callback) | 149 | if (tx->callback) |
73 | desc->async_tx.callback( | 150 | tx->callback(tx->callback_param); |
74 | desc->async_tx.callback_param); | ||
75 | 151 | ||
76 | /* unmap dma addresses | 152 | /* unmap dma addresses |
77 | * (unmap_single vs unmap_page?) | 153 | * (unmap_single vs unmap_page?) |
78 | */ | 154 | */ |
79 | if (desc->group_head && desc->unmap_len) { | 155 | if (desc->group_head && desc->unmap_len) { |
80 | struct iop_adma_desc_slot *unmap = desc->group_head; | 156 | if (iop_desc_is_pq(desc)) |
81 | struct device *dev = | 157 | iop_desc_unmap_pq(iop_chan, desc); |
82 | &iop_chan->device->pdev->dev; | 158 | else |
83 | u32 len = unmap->unmap_len; | 159 | iop_desc_unmap(iop_chan, desc); |
84 | enum dma_ctrl_flags flags = desc->async_tx.flags; | ||
85 | u32 src_cnt; | ||
86 | dma_addr_t addr; | ||
87 | dma_addr_t dest; | ||
88 | |||
89 | src_cnt = unmap->unmap_src_cnt; | ||
90 | dest = iop_desc_get_dest_addr(unmap, iop_chan); | ||
91 | if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP)) { | ||
92 | enum dma_data_direction dir; | ||
93 | |||
94 | if (src_cnt > 1) /* is xor? */ | ||
95 | dir = DMA_BIDIRECTIONAL; | ||
96 | else | ||
97 | dir = DMA_FROM_DEVICE; | ||
98 | |||
99 | dma_unmap_page(dev, dest, len, dir); | ||
100 | } | ||
101 | |||
102 | if (!(flags & DMA_COMPL_SKIP_SRC_UNMAP)) { | ||
103 | while (src_cnt--) { | ||
104 | addr = iop_desc_get_src_addr(unmap, | ||
105 | iop_chan, | ||
106 | src_cnt); | ||
107 | if (addr == dest) | ||
108 | continue; | ||
109 | dma_unmap_page(dev, addr, len, | ||
110 | DMA_TO_DEVICE); | ||
111 | } | ||
112 | } | ||
113 | desc->group_head = NULL; | ||
114 | } | 160 | } |
115 | } | 161 | } |
116 | 162 | ||
117 | /* run dependent operations */ | 163 | /* run dependent operations */ |
118 | dma_run_dependencies(&desc->async_tx); | 164 | dma_run_dependencies(tx); |
119 | 165 | ||
120 | return cookie; | 166 | return cookie; |
121 | } | 167 | } |
@@ -287,7 +333,12 @@ static void iop_adma_tasklet(unsigned long data) | |||
287 | { | 333 | { |
288 | struct iop_adma_chan *iop_chan = (struct iop_adma_chan *) data; | 334 | struct iop_adma_chan *iop_chan = (struct iop_adma_chan *) data; |
289 | 335 | ||
290 | spin_lock(&iop_chan->lock); | 336 | /* lockdep will flag depedency submissions as potentially |
337 | * recursive locking, this is not the case as a dependency | ||
338 | * submission will never recurse a channels submit routine. | ||
339 | * There are checks in async_tx.c to prevent this. | ||
340 | */ | ||
341 | spin_lock_nested(&iop_chan->lock, SINGLE_DEPTH_NESTING); | ||
291 | __iop_adma_slot_cleanup(iop_chan); | 342 | __iop_adma_slot_cleanup(iop_chan); |
292 | spin_unlock(&iop_chan->lock); | 343 | spin_unlock(&iop_chan->lock); |
293 | } | 344 | } |
@@ -696,6 +747,118 @@ iop_adma_prep_dma_xor_val(struct dma_chan *chan, dma_addr_t *dma_src, | |||
696 | return sw_desc ? &sw_desc->async_tx : NULL; | 747 | return sw_desc ? &sw_desc->async_tx : NULL; |
697 | } | 748 | } |
698 | 749 | ||
750 | static struct dma_async_tx_descriptor * | ||
751 | iop_adma_prep_dma_pq(struct dma_chan *chan, dma_addr_t *dst, dma_addr_t *src, | ||
752 | unsigned int src_cnt, const unsigned char *scf, size_t len, | ||
753 | unsigned long flags) | ||
754 | { | ||
755 | struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan); | ||
756 | struct iop_adma_desc_slot *sw_desc, *g; | ||
757 | int slot_cnt, slots_per_op; | ||
758 | int continue_srcs; | ||
759 | |||
760 | if (unlikely(!len)) | ||
761 | return NULL; | ||
762 | BUG_ON(len > IOP_ADMA_XOR_MAX_BYTE_COUNT); | ||
763 | |||
764 | dev_dbg(iop_chan->device->common.dev, | ||
765 | "%s src_cnt: %d len: %u flags: %lx\n", | ||
766 | __func__, src_cnt, len, flags); | ||
767 | |||
768 | if (dmaf_p_disabled_continue(flags)) | ||
769 | continue_srcs = 1+src_cnt; | ||
770 | else if (dmaf_continue(flags)) | ||
771 | continue_srcs = 3+src_cnt; | ||
772 | else | ||
773 | continue_srcs = 0+src_cnt; | ||
774 | |||
775 | spin_lock_bh(&iop_chan->lock); | ||
776 | slot_cnt = iop_chan_pq_slot_count(len, continue_srcs, &slots_per_op); | ||
777 | sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op); | ||
778 | if (sw_desc) { | ||
779 | int i; | ||
780 | |||
781 | g = sw_desc->group_head; | ||
782 | iop_desc_set_byte_count(g, iop_chan, len); | ||
783 | |||
784 | /* even if P is disabled its destination address (bits | ||
785 | * [3:0]) must match Q. It is ok if P points to an | ||
786 | * invalid address, it won't be written. | ||
787 | */ | ||
788 | if (flags & DMA_PREP_PQ_DISABLE_P) | ||
789 | dst[0] = dst[1] & 0x7; | ||
790 | |||
791 | iop_desc_set_pq_addr(g, dst); | ||
792 | sw_desc->unmap_src_cnt = src_cnt; | ||
793 | sw_desc->unmap_len = len; | ||
794 | sw_desc->async_tx.flags = flags; | ||
795 | for (i = 0; i < src_cnt; i++) | ||
796 | iop_desc_set_pq_src_addr(g, i, src[i], scf[i]); | ||
797 | |||
798 | /* if we are continuing a previous operation factor in | ||
799 | * the old p and q values, see the comment for dma_maxpq | ||
800 | * in include/linux/dmaengine.h | ||
801 | */ | ||
802 | if (dmaf_p_disabled_continue(flags)) | ||
803 | iop_desc_set_pq_src_addr(g, i++, dst[1], 1); | ||
804 | else if (dmaf_continue(flags)) { | ||
805 | iop_desc_set_pq_src_addr(g, i++, dst[0], 0); | ||
806 | iop_desc_set_pq_src_addr(g, i++, dst[1], 1); | ||
807 | iop_desc_set_pq_src_addr(g, i++, dst[1], 0); | ||
808 | } | ||
809 | iop_desc_init_pq(g, i, flags); | ||
810 | } | ||
811 | spin_unlock_bh(&iop_chan->lock); | ||
812 | |||
813 | return sw_desc ? &sw_desc->async_tx : NULL; | ||
814 | } | ||
815 | |||
816 | static struct dma_async_tx_descriptor * | ||
817 | iop_adma_prep_dma_pq_val(struct dma_chan *chan, dma_addr_t *pq, dma_addr_t *src, | ||
818 | unsigned int src_cnt, const unsigned char *scf, | ||
819 | size_t len, enum sum_check_flags *pqres, | ||
820 | unsigned long flags) | ||
821 | { | ||
822 | struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan); | ||
823 | struct iop_adma_desc_slot *sw_desc, *g; | ||
824 | int slot_cnt, slots_per_op; | ||
825 | |||
826 | if (unlikely(!len)) | ||
827 | return NULL; | ||
828 | BUG_ON(len > IOP_ADMA_XOR_MAX_BYTE_COUNT); | ||
829 | |||
830 | dev_dbg(iop_chan->device->common.dev, "%s src_cnt: %d len: %u\n", | ||
831 | __func__, src_cnt, len); | ||
832 | |||
833 | spin_lock_bh(&iop_chan->lock); | ||
834 | slot_cnt = iop_chan_pq_zero_sum_slot_count(len, src_cnt + 2, &slots_per_op); | ||
835 | sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op); | ||
836 | if (sw_desc) { | ||
837 | /* for validate operations p and q are tagged onto the | ||
838 | * end of the source list | ||
839 | */ | ||
840 | int pq_idx = src_cnt; | ||
841 | |||
842 | g = sw_desc->group_head; | ||
843 | iop_desc_init_pq_zero_sum(g, src_cnt+2, flags); | ||
844 | iop_desc_set_pq_zero_sum_byte_count(g, len); | ||
845 | g->pq_check_result = pqres; | ||
846 | pr_debug("\t%s: g->pq_check_result: %p\n", | ||
847 | __func__, g->pq_check_result); | ||
848 | sw_desc->unmap_src_cnt = src_cnt+2; | ||
849 | sw_desc->unmap_len = len; | ||
850 | sw_desc->async_tx.flags = flags; | ||
851 | while (src_cnt--) | ||
852 | iop_desc_set_pq_zero_sum_src_addr(g, src_cnt, | ||
853 | src[src_cnt], | ||
854 | scf[src_cnt]); | ||
855 | iop_desc_set_pq_zero_sum_addr(g, pq_idx, src); | ||
856 | } | ||
857 | spin_unlock_bh(&iop_chan->lock); | ||
858 | |||
859 | return sw_desc ? &sw_desc->async_tx : NULL; | ||
860 | } | ||
861 | |||
699 | static void iop_adma_free_chan_resources(struct dma_chan *chan) | 862 | static void iop_adma_free_chan_resources(struct dma_chan *chan) |
700 | { | 863 | { |
701 | struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan); | 864 | struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan); |
@@ -1105,6 +1268,170 @@ out: | |||
1105 | return err; | 1268 | return err; |
1106 | } | 1269 | } |
1107 | 1270 | ||
1271 | #ifdef CONFIG_MD_RAID6_PQ | ||
1272 | static int __devinit | ||
1273 | iop_adma_pq_zero_sum_self_test(struct iop_adma_device *device) | ||
1274 | { | ||
1275 | /* combined sources, software pq results, and extra hw pq results */ | ||
1276 | struct page *pq[IOP_ADMA_NUM_SRC_TEST+2+2]; | ||
1277 | /* ptr to the extra hw pq buffers defined above */ | ||
1278 | struct page **pq_hw = &pq[IOP_ADMA_NUM_SRC_TEST+2]; | ||
1279 | /* address conversion buffers (dma_map / page_address) */ | ||
1280 | void *pq_sw[IOP_ADMA_NUM_SRC_TEST+2]; | ||
1281 | dma_addr_t pq_src[IOP_ADMA_NUM_SRC_TEST]; | ||
1282 | dma_addr_t pq_dest[2]; | ||
1283 | |||
1284 | int i; | ||
1285 | struct dma_async_tx_descriptor *tx; | ||
1286 | struct dma_chan *dma_chan; | ||
1287 | dma_cookie_t cookie; | ||
1288 | u32 zero_sum_result; | ||
1289 | int err = 0; | ||
1290 | struct device *dev; | ||
1291 | |||
1292 | dev_dbg(device->common.dev, "%s\n", __func__); | ||
1293 | |||
1294 | for (i = 0; i < ARRAY_SIZE(pq); i++) { | ||
1295 | pq[i] = alloc_page(GFP_KERNEL); | ||
1296 | if (!pq[i]) { | ||
1297 | while (i--) | ||
1298 | __free_page(pq[i]); | ||
1299 | return -ENOMEM; | ||
1300 | } | ||
1301 | } | ||
1302 | |||
1303 | /* Fill in src buffers */ | ||
1304 | for (i = 0; i < IOP_ADMA_NUM_SRC_TEST; i++) { | ||
1305 | pq_sw[i] = page_address(pq[i]); | ||
1306 | memset(pq_sw[i], 0x11111111 * (1<<i), PAGE_SIZE); | ||
1307 | } | ||
1308 | pq_sw[i] = page_address(pq[i]); | ||
1309 | pq_sw[i+1] = page_address(pq[i+1]); | ||
1310 | |||
1311 | dma_chan = container_of(device->common.channels.next, | ||
1312 | struct dma_chan, | ||
1313 | device_node); | ||
1314 | if (iop_adma_alloc_chan_resources(dma_chan) < 1) { | ||
1315 | err = -ENODEV; | ||
1316 | goto out; | ||
1317 | } | ||
1318 | |||
1319 | dev = dma_chan->device->dev; | ||
1320 | |||
1321 | /* initialize the dests */ | ||
1322 | memset(page_address(pq_hw[0]), 0 , PAGE_SIZE); | ||
1323 | memset(page_address(pq_hw[1]), 0 , PAGE_SIZE); | ||
1324 | |||
1325 | /* test pq */ | ||
1326 | pq_dest[0] = dma_map_page(dev, pq_hw[0], 0, PAGE_SIZE, DMA_FROM_DEVICE); | ||
1327 | pq_dest[1] = dma_map_page(dev, pq_hw[1], 0, PAGE_SIZE, DMA_FROM_DEVICE); | ||
1328 | for (i = 0; i < IOP_ADMA_NUM_SRC_TEST; i++) | ||
1329 | pq_src[i] = dma_map_page(dev, pq[i], 0, PAGE_SIZE, | ||
1330 | DMA_TO_DEVICE); | ||
1331 | |||
1332 | tx = iop_adma_prep_dma_pq(dma_chan, pq_dest, pq_src, | ||
1333 | IOP_ADMA_NUM_SRC_TEST, (u8 *)raid6_gfexp, | ||
1334 | PAGE_SIZE, | ||
1335 | DMA_PREP_INTERRUPT | | ||
1336 | DMA_CTRL_ACK); | ||
1337 | |||
1338 | cookie = iop_adma_tx_submit(tx); | ||
1339 | iop_adma_issue_pending(dma_chan); | ||
1340 | msleep(8); | ||
1341 | |||
1342 | if (iop_adma_is_complete(dma_chan, cookie, NULL, NULL) != | ||
1343 | DMA_SUCCESS) { | ||
1344 | dev_err(dev, "Self-test pq timed out, disabling\n"); | ||
1345 | err = -ENODEV; | ||
1346 | goto free_resources; | ||
1347 | } | ||
1348 | |||
1349 | raid6_call.gen_syndrome(IOP_ADMA_NUM_SRC_TEST+2, PAGE_SIZE, pq_sw); | ||
1350 | |||
1351 | if (memcmp(pq_sw[IOP_ADMA_NUM_SRC_TEST], | ||
1352 | page_address(pq_hw[0]), PAGE_SIZE) != 0) { | ||
1353 | dev_err(dev, "Self-test p failed compare, disabling\n"); | ||
1354 | err = -ENODEV; | ||
1355 | goto free_resources; | ||
1356 | } | ||
1357 | if (memcmp(pq_sw[IOP_ADMA_NUM_SRC_TEST+1], | ||
1358 | page_address(pq_hw[1]), PAGE_SIZE) != 0) { | ||
1359 | dev_err(dev, "Self-test q failed compare, disabling\n"); | ||
1360 | err = -ENODEV; | ||
1361 | goto free_resources; | ||
1362 | } | ||
1363 | |||
1364 | /* test correct zero sum using the software generated pq values */ | ||
1365 | for (i = 0; i < IOP_ADMA_NUM_SRC_TEST + 2; i++) | ||
1366 | pq_src[i] = dma_map_page(dev, pq[i], 0, PAGE_SIZE, | ||
1367 | DMA_TO_DEVICE); | ||
1368 | |||
1369 | zero_sum_result = ~0; | ||
1370 | tx = iop_adma_prep_dma_pq_val(dma_chan, &pq_src[IOP_ADMA_NUM_SRC_TEST], | ||
1371 | pq_src, IOP_ADMA_NUM_SRC_TEST, | ||
1372 | raid6_gfexp, PAGE_SIZE, &zero_sum_result, | ||
1373 | DMA_PREP_INTERRUPT|DMA_CTRL_ACK); | ||
1374 | |||
1375 | cookie = iop_adma_tx_submit(tx); | ||
1376 | iop_adma_issue_pending(dma_chan); | ||
1377 | msleep(8); | ||
1378 | |||
1379 | if (iop_adma_is_complete(dma_chan, cookie, NULL, NULL) != | ||
1380 | DMA_SUCCESS) { | ||
1381 | dev_err(dev, "Self-test pq-zero-sum timed out, disabling\n"); | ||
1382 | err = -ENODEV; | ||
1383 | goto free_resources; | ||
1384 | } | ||
1385 | |||
1386 | if (zero_sum_result != 0) { | ||
1387 | dev_err(dev, "Self-test pq-zero-sum failed to validate: %x\n", | ||
1388 | zero_sum_result); | ||
1389 | err = -ENODEV; | ||
1390 | goto free_resources; | ||
1391 | } | ||
1392 | |||
1393 | /* test incorrect zero sum */ | ||
1394 | i = IOP_ADMA_NUM_SRC_TEST; | ||
1395 | memset(pq_sw[i] + 100, 0, 100); | ||
1396 | memset(pq_sw[i+1] + 200, 0, 200); | ||
1397 | for (i = 0; i < IOP_ADMA_NUM_SRC_TEST + 2; i++) | ||
1398 | pq_src[i] = dma_map_page(dev, pq[i], 0, PAGE_SIZE, | ||
1399 | DMA_TO_DEVICE); | ||
1400 | |||
1401 | zero_sum_result = 0; | ||
1402 | tx = iop_adma_prep_dma_pq_val(dma_chan, &pq_src[IOP_ADMA_NUM_SRC_TEST], | ||
1403 | pq_src, IOP_ADMA_NUM_SRC_TEST, | ||
1404 | raid6_gfexp, PAGE_SIZE, &zero_sum_result, | ||
1405 | DMA_PREP_INTERRUPT|DMA_CTRL_ACK); | ||
1406 | |||
1407 | cookie = iop_adma_tx_submit(tx); | ||
1408 | iop_adma_issue_pending(dma_chan); | ||
1409 | msleep(8); | ||
1410 | |||
1411 | if (iop_adma_is_complete(dma_chan, cookie, NULL, NULL) != | ||
1412 | DMA_SUCCESS) { | ||
1413 | dev_err(dev, "Self-test !pq-zero-sum timed out, disabling\n"); | ||
1414 | err = -ENODEV; | ||
1415 | goto free_resources; | ||
1416 | } | ||
1417 | |||
1418 | if (zero_sum_result != (SUM_CHECK_P_RESULT | SUM_CHECK_Q_RESULT)) { | ||
1419 | dev_err(dev, "Self-test !pq-zero-sum failed to validate: %x\n", | ||
1420 | zero_sum_result); | ||
1421 | err = -ENODEV; | ||
1422 | goto free_resources; | ||
1423 | } | ||
1424 | |||
1425 | free_resources: | ||
1426 | iop_adma_free_chan_resources(dma_chan); | ||
1427 | out: | ||
1428 | i = ARRAY_SIZE(pq); | ||
1429 | while (i--) | ||
1430 | __free_page(pq[i]); | ||
1431 | return err; | ||
1432 | } | ||
1433 | #endif | ||
1434 | |||
1108 | static int __devexit iop_adma_remove(struct platform_device *dev) | 1435 | static int __devexit iop_adma_remove(struct platform_device *dev) |
1109 | { | 1436 | { |
1110 | struct iop_adma_device *device = platform_get_drvdata(dev); | 1437 | struct iop_adma_device *device = platform_get_drvdata(dev); |
@@ -1195,6 +1522,13 @@ static int __devinit iop_adma_probe(struct platform_device *pdev) | |||
1195 | if (dma_has_cap(DMA_XOR_VAL, dma_dev->cap_mask)) | 1522 | if (dma_has_cap(DMA_XOR_VAL, dma_dev->cap_mask)) |
1196 | dma_dev->device_prep_dma_xor_val = | 1523 | dma_dev->device_prep_dma_xor_val = |
1197 | iop_adma_prep_dma_xor_val; | 1524 | iop_adma_prep_dma_xor_val; |
1525 | if (dma_has_cap(DMA_PQ, dma_dev->cap_mask)) { | ||
1526 | dma_set_maxpq(dma_dev, iop_adma_get_max_pq(), 0); | ||
1527 | dma_dev->device_prep_dma_pq = iop_adma_prep_dma_pq; | ||
1528 | } | ||
1529 | if (dma_has_cap(DMA_PQ_VAL, dma_dev->cap_mask)) | ||
1530 | dma_dev->device_prep_dma_pq_val = | ||
1531 | iop_adma_prep_dma_pq_val; | ||
1198 | if (dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask)) | 1532 | if (dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask)) |
1199 | dma_dev->device_prep_dma_interrupt = | 1533 | dma_dev->device_prep_dma_interrupt = |
1200 | iop_adma_prep_dma_interrupt; | 1534 | iop_adma_prep_dma_interrupt; |
@@ -1248,13 +1582,28 @@ static int __devinit iop_adma_probe(struct platform_device *pdev) | |||
1248 | } | 1582 | } |
1249 | 1583 | ||
1250 | if (dma_has_cap(DMA_XOR, dma_dev->cap_mask) || | 1584 | if (dma_has_cap(DMA_XOR, dma_dev->cap_mask) || |
1251 | dma_has_cap(DMA_MEMSET, dma_dev->cap_mask)) { | 1585 | dma_has_cap(DMA_MEMSET, dma_dev->cap_mask)) { |
1252 | ret = iop_adma_xor_val_self_test(adev); | 1586 | ret = iop_adma_xor_val_self_test(adev); |
1253 | dev_dbg(&pdev->dev, "xor self test returned %d\n", ret); | 1587 | dev_dbg(&pdev->dev, "xor self test returned %d\n", ret); |
1254 | if (ret) | 1588 | if (ret) |
1255 | goto err_free_iop_chan; | 1589 | goto err_free_iop_chan; |
1256 | } | 1590 | } |
1257 | 1591 | ||
1592 | if (dma_has_cap(DMA_PQ, dma_dev->cap_mask) && | ||
1593 | dma_has_cap(DMA_PQ_VAL, dma_dev->cap_mask)) { | ||
1594 | #ifdef CONFIG_MD_RAID6_PQ | ||
1595 | ret = iop_adma_pq_zero_sum_self_test(adev); | ||
1596 | dev_dbg(&pdev->dev, "pq self test returned %d\n", ret); | ||
1597 | #else | ||
1598 | /* can not test raid6, so do not publish capability */ | ||
1599 | dma_cap_clear(DMA_PQ, dma_dev->cap_mask); | ||
1600 | dma_cap_clear(DMA_PQ_VAL, dma_dev->cap_mask); | ||
1601 | ret = 0; | ||
1602 | #endif | ||
1603 | if (ret) | ||
1604 | goto err_free_iop_chan; | ||
1605 | } | ||
1606 | |||
1258 | dev_printk(KERN_INFO, &pdev->dev, "Intel(R) IOP: " | 1607 | dev_printk(KERN_INFO, &pdev->dev, "Intel(R) IOP: " |
1259 | "( %s%s%s%s%s%s%s)\n", | 1608 | "( %s%s%s%s%s%s%s)\n", |
1260 | dma_has_cap(DMA_PQ, dma_dev->cap_mask) ? "pq " : "", | 1609 | dma_has_cap(DMA_PQ, dma_dev->cap_mask) ? "pq " : "", |