.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright(c) 2007 Yuri Tikhonov <yur@emcraft.com> |
---|
3 | 4 | * Copyright(c) 2009 Intel Corporation |
---|
4 | | - * |
---|
5 | | - * This program is free software; you can redistribute it and/or modify it |
---|
6 | | - * under the terms of the GNU General Public License as published by the Free |
---|
7 | | - * Software Foundation; either version 2 of the License, or (at your option) |
---|
8 | | - * any later version. |
---|
9 | | - * |
---|
10 | | - * This program is distributed in the hope that it will be useful, but WITHOUT |
---|
11 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
---|
12 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
---|
13 | | - * more details. |
---|
14 | | - * |
---|
15 | | - * You should have received a copy of the GNU General Public License along with |
---|
16 | | - * this program; if not, write to the Free Software Foundation, Inc., 59 |
---|
17 | | - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
---|
18 | | - * |
---|
19 | | - * The full GNU General Public License is included in this distribution in the |
---|
20 | | - * file called COPYING. |
---|
21 | 5 | */ |
---|
22 | 6 | #include <linux/kernel.h> |
---|
23 | 7 | #include <linux/interrupt.h> |
---|
.. | .. |
---|
120 | 104 | * do_sync_gen_syndrome - synchronously calculate a raid6 syndrome |
---|
121 | 105 | */ |
---|
122 | 106 | static void |
---|
123 | | -do_sync_gen_syndrome(struct page **blocks, unsigned int offset, int disks, |
---|
| 107 | +do_sync_gen_syndrome(struct page **blocks, unsigned int *offsets, int disks, |
---|
124 | 108 | size_t len, struct async_submit_ctl *submit) |
---|
125 | 109 | { |
---|
126 | 110 | void **srcs; |
---|
.. | .. |
---|
137 | 121 | BUG_ON(i > disks - 3); /* P or Q can't be zero */ |
---|
138 | 122 | srcs[i] = (void*)raid6_empty_zero_page; |
---|
139 | 123 | } else { |
---|
140 | | - srcs[i] = page_address(blocks[i]) + offset; |
---|
| 124 | + srcs[i] = page_address(blocks[i]) + offsets[i]; |
---|
| 125 | + |
---|
141 | 126 | if (i < disks - 2) { |
---|
142 | 127 | stop = i; |
---|
143 | 128 | if (start == -1) |
---|
.. | .. |
---|
154 | 139 | async_tx_sync_epilog(submit); |
---|
155 | 140 | } |
---|
156 | 141 | |
---|
| 142 | +static inline bool |
---|
| 143 | +is_dma_pq_aligned_offs(struct dma_device *dev, unsigned int *offs, |
---|
| 144 | + int src_cnt, size_t len) |
---|
| 145 | +{ |
---|
| 146 | + int i; |
---|
| 147 | + |
---|
| 148 | + for (i = 0; i < src_cnt; i++) { |
---|
| 149 | + if (!is_dma_pq_aligned(dev, offs[i], 0, len)) |
---|
| 150 | + return false; |
---|
| 151 | + } |
---|
| 152 | + return true; |
---|
| 153 | +} |
---|
| 154 | + |
---|
157 | 155 | /** |
---|
158 | 156 | * async_gen_syndrome - asynchronously calculate a raid6 syndrome |
---|
159 | 157 | * @blocks: source blocks from idx 0..disks-3, P @ disks-2 and Q @ disks-1 |
---|
160 | | - * @offset: common offset into each block (src and dest) to start transaction |
---|
| 158 | + * @offsets: offset array into each block (src and dest) to start transaction |
---|
161 | 159 | * @disks: number of blocks (including missing P or Q, see below) |
---|
162 | 160 | * @len: length of operation in bytes |
---|
163 | 161 | * @submit: submission/completion modifiers |
---|
.. | .. |
---|
176 | 174 | * path. |
---|
177 | 175 | */ |
---|
178 | 176 | struct dma_async_tx_descriptor * |
---|
179 | | -async_gen_syndrome(struct page **blocks, unsigned int offset, int disks, |
---|
| 177 | +async_gen_syndrome(struct page **blocks, unsigned int *offsets, int disks, |
---|
180 | 178 | size_t len, struct async_submit_ctl *submit) |
---|
181 | 179 | { |
---|
182 | 180 | int src_cnt = disks - 2; |
---|
.. | .. |
---|
195 | 193 | if (unmap && !(submit->flags & ASYNC_TX_PQ_XOR_DST) && |
---|
196 | 194 | (src_cnt <= dma_maxpq(device, 0) || |
---|
197 | 195 | dma_maxpq(device, DMA_PREP_CONTINUE) > 0) && |
---|
198 | | - is_dma_pq_aligned(device, offset, 0, len)) { |
---|
| 196 | + is_dma_pq_aligned_offs(device, offsets, disks, len)) { |
---|
199 | 197 | struct dma_async_tx_descriptor *tx; |
---|
200 | 198 | enum dma_ctrl_flags dma_flags = 0; |
---|
201 | 199 | unsigned char coefs[MAX_DISKS]; |
---|
.. | .. |
---|
212 | 210 | for (i = 0, j = 0; i < src_cnt; i++) { |
---|
213 | 211 | if (blocks[i] == NULL) |
---|
214 | 212 | continue; |
---|
215 | | - unmap->addr[j] = dma_map_page(device->dev, blocks[i], offset, |
---|
216 | | - len, DMA_TO_DEVICE); |
---|
| 213 | + unmap->addr[j] = dma_map_page(device->dev, blocks[i], |
---|
| 214 | + offsets[i], len, DMA_TO_DEVICE); |
---|
217 | 215 | coefs[j] = raid6_gfexp[i]; |
---|
218 | 216 | unmap->to_cnt++; |
---|
219 | 217 | j++; |
---|
.. | .. |
---|
226 | 224 | unmap->bidi_cnt++; |
---|
227 | 225 | if (P(blocks, disks)) |
---|
228 | 226 | unmap->addr[j++] = dma_map_page(device->dev, P(blocks, disks), |
---|
229 | | - offset, len, DMA_BIDIRECTIONAL); |
---|
| 227 | + P(offsets, disks), |
---|
| 228 | + len, DMA_BIDIRECTIONAL); |
---|
230 | 229 | else { |
---|
231 | 230 | unmap->addr[j++] = 0; |
---|
232 | 231 | dma_flags |= DMA_PREP_PQ_DISABLE_P; |
---|
.. | .. |
---|
235 | 234 | unmap->bidi_cnt++; |
---|
236 | 235 | if (Q(blocks, disks)) |
---|
237 | 236 | unmap->addr[j++] = dma_map_page(device->dev, Q(blocks, disks), |
---|
238 | | - offset, len, DMA_BIDIRECTIONAL); |
---|
| 237 | + Q(offsets, disks), |
---|
| 238 | + len, DMA_BIDIRECTIONAL); |
---|
239 | 239 | else { |
---|
240 | 240 | unmap->addr[j++] = 0; |
---|
241 | 241 | dma_flags |= DMA_PREP_PQ_DISABLE_Q; |
---|
.. | .. |
---|
256 | 256 | |
---|
257 | 257 | if (!P(blocks, disks)) { |
---|
258 | 258 | P(blocks, disks) = pq_scribble_page; |
---|
259 | | - BUG_ON(len + offset > PAGE_SIZE); |
---|
| 259 | + P(offsets, disks) = 0; |
---|
260 | 260 | } |
---|
261 | 261 | if (!Q(blocks, disks)) { |
---|
262 | 262 | Q(blocks, disks) = pq_scribble_page; |
---|
263 | | - BUG_ON(len + offset > PAGE_SIZE); |
---|
| 263 | + Q(offsets, disks) = 0; |
---|
264 | 264 | } |
---|
265 | | - do_sync_gen_syndrome(blocks, offset, disks, len, submit); |
---|
| 265 | + do_sync_gen_syndrome(blocks, offsets, disks, len, submit); |
---|
266 | 266 | |
---|
267 | 267 | return NULL; |
---|
268 | 268 | } |
---|
.. | .. |
---|
286 | 286 | * @len: length of operation in bytes |
---|
287 | 287 | * @pqres: on val failure SUM_CHECK_P_RESULT and/or SUM_CHECK_Q_RESULT are set |
---|
288 | 288 | * @spare: temporary result buffer for the synchronous case |
---|
| 289 | + * @s_off: spare buffer page offset |
---|
289 | 290 | * @submit: submission / completion modifiers |
---|
290 | 291 | * |
---|
291 | 292 | * The same notes from async_gen_syndrome apply to the 'blocks', |
---|
.. | .. |
---|
294 | 295 | * specified. |
---|
295 | 296 | */ |
---|
296 | 297 | struct dma_async_tx_descriptor * |
---|
297 | | -async_syndrome_val(struct page **blocks, unsigned int offset, int disks, |
---|
| 298 | +async_syndrome_val(struct page **blocks, unsigned int *offsets, int disks, |
---|
298 | 299 | size_t len, enum sum_check_flags *pqres, struct page *spare, |
---|
299 | | - struct async_submit_ctl *submit) |
---|
| 300 | + unsigned int s_off, struct async_submit_ctl *submit) |
---|
300 | 301 | { |
---|
301 | 302 | struct dma_chan *chan = pq_val_chan(submit, blocks, disks, len); |
---|
302 | 303 | struct dma_device *device = chan ? chan->device : NULL; |
---|
.. | .. |
---|
311 | 312 | unmap = dmaengine_get_unmap_data(device->dev, disks, GFP_NOWAIT); |
---|
312 | 313 | |
---|
313 | 314 | if (unmap && disks <= dma_maxpq(device, 0) && |
---|
314 | | - is_dma_pq_aligned(device, offset, 0, len)) { |
---|
| 315 | + is_dma_pq_aligned_offs(device, offsets, disks, len)) { |
---|
315 | 316 | struct device *dev = device->dev; |
---|
316 | 317 | dma_addr_t pq[2]; |
---|
317 | 318 | int i, j = 0, src_cnt = 0; |
---|
.. | .. |
---|
323 | 324 | for (i = 0; i < disks-2; i++) |
---|
324 | 325 | if (likely(blocks[i])) { |
---|
325 | 326 | unmap->addr[j] = dma_map_page(dev, blocks[i], |
---|
326 | | - offset, len, |
---|
| 327 | + offsets[i], len, |
---|
327 | 328 | DMA_TO_DEVICE); |
---|
328 | 329 | coefs[j] = raid6_gfexp[i]; |
---|
329 | 330 | unmap->to_cnt++; |
---|
.. | .. |
---|
336 | 337 | dma_flags |= DMA_PREP_PQ_DISABLE_P; |
---|
337 | 338 | } else { |
---|
338 | 339 | pq[0] = dma_map_page(dev, P(blocks, disks), |
---|
339 | | - offset, len, |
---|
| 340 | + P(offsets, disks), len, |
---|
340 | 341 | DMA_TO_DEVICE); |
---|
341 | 342 | unmap->addr[j++] = pq[0]; |
---|
342 | 343 | unmap->to_cnt++; |
---|
.. | .. |
---|
346 | 347 | dma_flags |= DMA_PREP_PQ_DISABLE_Q; |
---|
347 | 348 | } else { |
---|
348 | 349 | pq[1] = dma_map_page(dev, Q(blocks, disks), |
---|
349 | | - offset, len, |
---|
| 350 | + Q(offsets, disks), len, |
---|
350 | 351 | DMA_TO_DEVICE); |
---|
351 | 352 | unmap->addr[j++] = pq[1]; |
---|
352 | 353 | unmap->to_cnt++; |
---|
.. | .. |
---|
371 | 372 | async_tx_submit(chan, tx, submit); |
---|
372 | 373 | } else { |
---|
373 | 374 | struct page *p_src = P(blocks, disks); |
---|
| 375 | + unsigned int p_off = P(offsets, disks); |
---|
374 | 376 | struct page *q_src = Q(blocks, disks); |
---|
| 377 | + unsigned int q_off = Q(offsets, disks); |
---|
375 | 378 | enum async_tx_flags flags_orig = submit->flags; |
---|
376 | 379 | dma_async_tx_callback cb_fn_orig = submit->cb_fn; |
---|
377 | 380 | void *scribble = submit->scribble; |
---|
.. | .. |
---|
397 | 400 | if (p_src) { |
---|
398 | 401 | init_async_submit(submit, ASYNC_TX_XOR_ZERO_DST, NULL, |
---|
399 | 402 | NULL, NULL, scribble); |
---|
400 | | - tx = async_xor(spare, blocks, offset, disks-2, len, submit); |
---|
| 403 | + tx = async_xor_offs(spare, s_off, |
---|
| 404 | + blocks, offsets, disks-2, len, submit); |
---|
401 | 405 | async_tx_quiesce(&tx); |
---|
402 | | - p = page_address(p_src) + offset; |
---|
403 | | - s = page_address(spare) + offset; |
---|
| 406 | + p = page_address(p_src) + p_off; |
---|
| 407 | + s = page_address(spare) + s_off; |
---|
404 | 408 | *pqres |= !!memcmp(p, s, len) << SUM_CHECK_P; |
---|
405 | 409 | } |
---|
406 | 410 | |
---|
407 | 411 | if (q_src) { |
---|
408 | 412 | P(blocks, disks) = NULL; |
---|
409 | 413 | Q(blocks, disks) = spare; |
---|
| 414 | + Q(offsets, disks) = s_off; |
---|
410 | 415 | init_async_submit(submit, 0, NULL, NULL, NULL, scribble); |
---|
411 | | - tx = async_gen_syndrome(blocks, offset, disks, len, submit); |
---|
| 416 | + tx = async_gen_syndrome(blocks, offsets, disks, |
---|
| 417 | + len, submit); |
---|
412 | 418 | async_tx_quiesce(&tx); |
---|
413 | | - q = page_address(q_src) + offset; |
---|
414 | | - s = page_address(spare) + offset; |
---|
| 419 | + q = page_address(q_src) + q_off; |
---|
| 420 | + s = page_address(spare) + s_off; |
---|
415 | 421 | *pqres |= !!memcmp(q, s, len) << SUM_CHECK_Q; |
---|
416 | 422 | } |
---|
417 | 423 | |
---|
418 | 424 | /* restore P, Q and submit */ |
---|
419 | 425 | P(blocks, disks) = p_src; |
---|
| 426 | + P(offsets, disks) = p_off; |
---|
420 | 427 | Q(blocks, disks) = q_src; |
---|
| 428 | + Q(offsets, disks) = q_off; |
---|
421 | 429 | |
---|
422 | 430 | submit->cb_fn = cb_fn_orig; |
---|
423 | 431 | submit->cb_param = cb_param_orig; |
---|