diff options
author | Ladislav Michl <ladis@linux-mips.org> | 2018-05-02 06:41:32 -0400 |
---|---|---|
committer | Boris Brezillon <boris.brezillon@bootlin.com> | 2018-05-02 09:17:18 -0400 |
commit | 6732cfd4cac514b556f36b518670af91c8bdf19a (patch) | |
tree | 628fd72e2b4ea3398cb71ef87e9bdd1a4c8da4e1 | |
parent | 6da6c0db5316275015e8cc2959f12a17584aeb64 (diff) |
mtd: onenand: omap2: Disable DMA for HIGHMEM buffers
dma_map_single does not work for vmalloc-ed buffers,
so disable DMA in this case.
Signed-off-by: Ladislav Michl <ladis@linux-mips.org>
Reported-by: "H. Nikolaus Schaller" <hns@goldelico.com>
Tested-by: "H. Nikolaus Schaller" <hns@goldelico.com>
Reviewed-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
-rw-r--r-- | drivers/mtd/nand/onenand/omap2.c | 105 |
1 files changed, 38 insertions, 67 deletions
diff --git a/drivers/mtd/nand/onenand/omap2.c b/drivers/mtd/nand/onenand/omap2.c index 9c159f0dd9a6..321137158ff3 100644 --- a/drivers/mtd/nand/onenand/omap2.c +++ b/drivers/mtd/nand/onenand/omap2.c | |||
@@ -375,56 +375,42 @@ static int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area, | |||
375 | { | 375 | { |
376 | struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); | 376 | struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); |
377 | struct onenand_chip *this = mtd->priv; | 377 | struct onenand_chip *this = mtd->priv; |
378 | dma_addr_t dma_src, dma_dst; | 378 | struct device *dev = &c->pdev->dev; |
379 | int bram_offset; | ||
380 | void *buf = (void *)buffer; | 379 | void *buf = (void *)buffer; |
380 | dma_addr_t dma_src, dma_dst; | ||
381 | int bram_offset, err; | ||
381 | size_t xtra; | 382 | size_t xtra; |
382 | int ret; | ||
383 | 383 | ||
384 | bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset; | 384 | bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset; |
385 | if (bram_offset & 3 || (size_t)buf & 3 || count < 384) | 385 | /* |
386 | goto out_copy; | 386 | * If the buffer address is not DMA-able, len is not long enough to make |
387 | 387 | * DMA transfers profitable or panic_write() may be in an interrupt | |
388 | /* panic_write() may be in an interrupt context */ | 388 | * context fallback to PIO mode. |
389 | if (in_interrupt() || oops_in_progress) | 389 | */ |
390 | if (!virt_addr_valid(buf) || bram_offset & 3 || (size_t)buf & 3 || | ||
391 | count < 384 || in_interrupt() || oops_in_progress ) | ||
390 | goto out_copy; | 392 | goto out_copy; |
391 | 393 | ||
392 | if (buf >= high_memory) { | ||
393 | struct page *p1; | ||
394 | |||
395 | if (((size_t)buf & PAGE_MASK) != | ||
396 | ((size_t)(buf + count - 1) & PAGE_MASK)) | ||
397 | goto out_copy; | ||
398 | p1 = vmalloc_to_page(buf); | ||
399 | if (!p1) | ||
400 | goto out_copy; | ||
401 | buf = page_address(p1) + ((size_t)buf & ~PAGE_MASK); | ||
402 | } | ||
403 | |||
404 | xtra = count & 3; | 394 | xtra = count & 3; |
405 | if (xtra) { | 395 | if (xtra) { |
406 | count -= xtra; | 396 | count -= xtra; |
407 | memcpy(buf + count, this->base + bram_offset + count, xtra); | 397 | memcpy(buf + count, this->base + bram_offset + count, xtra); |
408 | } | 398 | } |
409 | 399 | ||
400 | dma_dst = dma_map_single(dev, buf, count, DMA_FROM_DEVICE); | ||
410 | dma_src = c->phys_base + bram_offset; | 401 | dma_src = c->phys_base + bram_offset; |
411 | dma_dst = dma_map_single(&c->pdev->dev, buf, count, DMA_FROM_DEVICE); | ||
412 | if (dma_mapping_error(&c->pdev->dev, dma_dst)) { | ||
413 | dev_err(&c->pdev->dev, | ||
414 | "Couldn't DMA map a %d byte buffer\n", | ||
415 | count); | ||
416 | goto out_copy; | ||
417 | } | ||
418 | 402 | ||
419 | ret = omap2_onenand_dma_transfer(c, dma_src, dma_dst, count); | 403 | if (dma_mapping_error(dev, dma_dst)) { |
420 | dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_FROM_DEVICE); | 404 | dev_err(dev, "Couldn't DMA map a %d byte buffer\n", count); |
421 | |||
422 | if (ret) { | ||
423 | dev_err(&c->pdev->dev, "timeout waiting for DMA\n"); | ||
424 | goto out_copy; | 405 | goto out_copy; |
425 | } | 406 | } |
426 | 407 | ||
427 | return 0; | 408 | err = omap2_onenand_dma_transfer(c, dma_src, dma_dst, count); |
409 | dma_unmap_single(dev, dma_dst, count, DMA_FROM_DEVICE); | ||
410 | if (!err) | ||
411 | return 0; | ||
412 | |||
413 | dev_err(dev, "timeout waiting for DMA\n"); | ||
428 | 414 | ||
429 | out_copy: | 415 | out_copy: |
430 | memcpy(buf, this->base + bram_offset, count); | 416 | memcpy(buf, this->base + bram_offset, count); |
@@ -437,49 +423,34 @@ static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area, | |||
437 | { | 423 | { |
438 | struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); | 424 | struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); |
439 | struct onenand_chip *this = mtd->priv; | 425 | struct onenand_chip *this = mtd->priv; |
440 | dma_addr_t dma_src, dma_dst; | 426 | struct device *dev = &c->pdev->dev; |
441 | int bram_offset; | ||
442 | void *buf = (void *)buffer; | 427 | void *buf = (void *)buffer; |
443 | int ret; | 428 | dma_addr_t dma_src, dma_dst; |
429 | int bram_offset, err; | ||
444 | 430 | ||
445 | bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset; | 431 | bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset; |
446 | if (bram_offset & 3 || (size_t)buf & 3 || count < 384) | 432 | /* |
447 | goto out_copy; | 433 | * If the buffer address is not DMA-able, len is not long enough to make |
448 | 434 | * DMA transfers profitable or panic_write() may be in an interrupt | |
449 | /* panic_write() may be in an interrupt context */ | 435 | * context fallback to PIO mode. |
450 | if (in_interrupt() || oops_in_progress) | 436 | */ |
437 | if (!virt_addr_valid(buf) || bram_offset & 3 || (size_t)buf & 3 || | ||
438 | count < 384 || in_interrupt() || oops_in_progress ) | ||
451 | goto out_copy; | 439 | goto out_copy; |
452 | 440 | ||
453 | if (buf >= high_memory) { | 441 | dma_src = dma_map_single(dev, buf, count, DMA_TO_DEVICE); |
454 | struct page *p1; | ||
455 | |||
456 | if (((size_t)buf & PAGE_MASK) != | ||
457 | ((size_t)(buf + count - 1) & PAGE_MASK)) | ||
458 | goto out_copy; | ||
459 | p1 = vmalloc_to_page(buf); | ||
460 | if (!p1) | ||
461 | goto out_copy; | ||
462 | buf = page_address(p1) + ((size_t)buf & ~PAGE_MASK); | ||
463 | } | ||
464 | |||
465 | dma_src = dma_map_single(&c->pdev->dev, buf, count, DMA_TO_DEVICE); | ||
466 | dma_dst = c->phys_base + bram_offset; | 442 | dma_dst = c->phys_base + bram_offset; |
467 | if (dma_mapping_error(&c->pdev->dev, dma_src)) { | 443 | if (dma_mapping_error(dev, dma_src)) { |
468 | dev_err(&c->pdev->dev, | 444 | dev_err(dev, "Couldn't DMA map a %d byte buffer\n", count); |
469 | "Couldn't DMA map a %d byte buffer\n", | ||
470 | count); | ||
471 | return -1; | ||
472 | } | ||
473 | |||
474 | ret = omap2_onenand_dma_transfer(c, dma_src, dma_dst, count); | ||
475 | dma_unmap_single(&c->pdev->dev, dma_src, count, DMA_TO_DEVICE); | ||
476 | |||
477 | if (ret) { | ||
478 | dev_err(&c->pdev->dev, "timeout waiting for DMA\n"); | ||
479 | goto out_copy; | 445 | goto out_copy; |
480 | } | 446 | } |
481 | 447 | ||
482 | return 0; | 448 | err = omap2_onenand_dma_transfer(c, dma_src, dma_dst, count); |
449 | dma_unmap_page(dev, dma_src, count, DMA_TO_DEVICE); | ||
450 | if (!err) | ||
451 | return 0; | ||
452 | |||
453 | dev_err(dev, "timeout waiting for DMA\n"); | ||
483 | 454 | ||
484 | out_copy: | 455 | out_copy: |
485 | memcpy(this->base + bram_offset, buf, count); | 456 | memcpy(this->base + bram_offset, buf, count); |