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