Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mtd: spi-nor: always use bounce buffer for register read/writes

spi-mem layer expects all buffers passed to it to be DMA'able. But
spi-nor layer mostly allocates buffers on stack for reading/writing to
registers and therefore are not DMA'able. Introduce bounce buffer to be
used to read/write to registers. This ensures that buffer passed to
spi-mem layer during register read/writes is DMA'able. With this change
nor->cmd-buf is no longer used, so drop it.

Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>

authored by

Vignesh Raghavendra and committed by
Tudor Ambarus
f173f26a 5f9e832c

+49 -38
+44 -36
drivers/mtd/spi-nor/spi-nor.c
··· 296 296 static int read_sr(struct spi_nor *nor) 297 297 { 298 298 int ret; 299 - u8 val; 300 299 301 - ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val, 1); 300 + ret = nor->read_reg(nor, SPINOR_OP_RDSR, nor->bouncebuf, 1); 302 301 if (ret < 0) { 303 302 pr_err("error %d reading SR\n", (int) ret); 304 303 return ret; 305 304 } 306 305 307 - return val; 306 + return nor->bouncebuf[0]; 308 307 } 309 308 310 309 /* ··· 314 315 static int read_fsr(struct spi_nor *nor) 315 316 { 316 317 int ret; 317 - u8 val; 318 318 319 - ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val, 1); 319 + ret = nor->read_reg(nor, SPINOR_OP_RDFSR, nor->bouncebuf, 1); 320 320 if (ret < 0) { 321 321 pr_err("error %d reading FSR\n", ret); 322 322 return ret; 323 323 } 324 324 325 - return val; 325 + return nor->bouncebuf[0]; 326 326 } 327 327 328 328 /* ··· 332 334 static int read_cr(struct spi_nor *nor) 333 335 { 334 336 int ret; 335 - u8 val; 336 337 337 - ret = nor->read_reg(nor, SPINOR_OP_RDCR, &val, 1); 338 + ret = nor->read_reg(nor, SPINOR_OP_RDCR, nor->bouncebuf, 1); 338 339 if (ret < 0) { 339 340 dev_err(nor->dev, "error %d reading CR\n", ret); 340 341 return ret; 341 342 } 342 343 343 - return val; 344 + return nor->bouncebuf[0]; 344 345 } 345 346 346 347 /* ··· 348 351 */ 349 352 static int write_sr(struct spi_nor *nor, u8 val) 350 353 { 351 - nor->cmd_buf[0] = val; 352 - return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1); 354 + nor->bouncebuf[0] = val; 355 + return nor->write_reg(nor, SPINOR_OP_WRSR, nor->bouncebuf, 1); 353 356 } 354 357 355 358 /* ··· 497 500 * We must clear the register to enable normal behavior. 498 501 */ 499 502 write_enable(nor); 500 - nor->cmd_buf[0] = 0; 501 - nor->write_reg(nor, SPINOR_OP_WREAR, nor->cmd_buf, 1); 503 + nor->bouncebuf[0] = 0; 504 + nor->write_reg(nor, SPINOR_OP_WREAR, 505 + nor->bouncebuf, 1); 502 506 write_disable(nor); 503 507 } 504 508 505 509 return status; 506 510 default: 507 511 /* Spansion style */ 508 - nor->cmd_buf[0] = enable << 7; 509 - return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1); 512 + nor->bouncebuf[0] = enable << 7; 513 + return nor->write_reg(nor, SPINOR_OP_BRWR, nor->bouncebuf, 1); 510 514 } 511 515 } 512 516 513 517 static int s3an_sr_ready(struct spi_nor *nor) 514 518 { 515 519 int ret; 516 - u8 val; 517 520 518 - ret = nor->read_reg(nor, SPINOR_OP_XRDSR, &val, 1); 521 + ret = nor->read_reg(nor, SPINOR_OP_XRDSR, nor->bouncebuf, 1); 519 522 if (ret < 0) { 520 523 dev_err(nor->dev, "error %d reading XRDSR\n", (int) ret); 521 524 return ret; 522 525 } 523 526 524 - return !!(val & XSR_RDY); 527 + return !!(nor->bouncebuf[0] & XSR_RDY); 525 528 } 526 529 527 530 static int spi_nor_sr_ready(struct spi_nor *nor) ··· 680 683 */ 681 684 static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr) 682 685 { 683 - u8 buf[SPI_NOR_MAX_ADDR_WIDTH]; 684 686 int i; 685 687 686 688 if (nor->flags & SNOR_F_S3AN_ADDR_DEFAULT) ··· 693 697 * control 694 698 */ 695 699 for (i = nor->addr_width - 1; i >= 0; i--) { 696 - buf[i] = addr & 0xff; 700 + nor->bouncebuf[i] = addr & 0xff; 697 701 addr >>= 8; 698 702 } 699 703 700 - return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width); 704 + return nor->write_reg(nor, nor->erase_opcode, nor->bouncebuf, 705 + nor->addr_width); 701 706 } 702 707 703 708 /** ··· 1482 1485 */ 1483 1486 static int spansion_quad_enable(struct spi_nor *nor) 1484 1487 { 1485 - u8 sr_cr[2] = {0, CR_QUAD_EN_SPAN}; 1488 + u8 *sr_cr = nor->bouncebuf; 1486 1489 int ret; 1487 1490 1491 + sr_cr[0] = 0; 1492 + sr_cr[1] = CR_QUAD_EN_SPAN; 1488 1493 ret = write_sr_cr(nor, sr_cr); 1489 1494 if (ret) 1490 1495 return ret; ··· 1516 1517 */ 1517 1518 static int spansion_no_read_cr_quad_enable(struct spi_nor *nor) 1518 1519 { 1519 - u8 sr_cr[2]; 1520 + u8 *sr_cr = nor->bouncebuf; 1520 1521 int ret; 1521 1522 1522 1523 /* Keep the current value of the Status Register. */ ··· 1547 1548 static int spansion_read_cr_quad_enable(struct spi_nor *nor) 1548 1549 { 1549 1550 struct device *dev = nor->dev; 1550 - u8 sr_cr[2]; 1551 + u8 *sr_cr = nor->bouncebuf; 1551 1552 int ret; 1552 1553 1553 1554 /* Check current Quad Enable bit value. */ ··· 1598 1599 */ 1599 1600 static int sr2_bit7_quad_enable(struct spi_nor *nor) 1600 1601 { 1601 - u8 sr2; 1602 + u8 *sr2 = nor->bouncebuf; 1602 1603 int ret; 1603 1604 1604 1605 /* Check current Quad Enable bit value. */ 1605 - ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1); 1606 + ret = nor->read_reg(nor, SPINOR_OP_RDSR2, sr2, 1); 1606 1607 if (ret) 1607 1608 return ret; 1608 - if (sr2 & SR2_QUAD_EN_BIT7) 1609 + if (*sr2 & SR2_QUAD_EN_BIT7) 1609 1610 return 0; 1610 1611 1611 1612 /* Update the Quad Enable bit. */ 1612 - sr2 |= SR2_QUAD_EN_BIT7; 1613 + *sr2 |= SR2_QUAD_EN_BIT7; 1613 1614 1614 1615 write_enable(nor); 1615 1616 1616 - ret = nor->write_reg(nor, SPINOR_OP_WRSR2, &sr2, 1); 1617 + ret = nor->write_reg(nor, SPINOR_OP_WRSR2, sr2, 1); 1617 1618 if (ret < 0) { 1618 1619 dev_err(nor->dev, "error while writing status register 2\n"); 1619 1620 return -EINVAL; ··· 1626 1627 } 1627 1628 1628 1629 /* Read back and check it. */ 1629 - ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1); 1630 - if (!(ret > 0 && (sr2 & SR2_QUAD_EN_BIT7))) { 1630 + ret = nor->read_reg(nor, SPINOR_OP_RDSR2, sr2, 1); 1631 + if (!(ret > 0 && (*sr2 & SR2_QUAD_EN_BIT7))) { 1631 1632 dev_err(nor->dev, "SR2 Quad bit not set\n"); 1632 1633 return -EINVAL; 1633 1634 } ··· 1686 1687 { 1687 1688 int ret; 1688 1689 u8 mask = SR_BP2 | SR_BP1 | SR_BP0; 1689 - u8 sr_cr[2] = {0}; 1690 + u8 *sr_cr = nor->bouncebuf; 1690 1691 1691 1692 /* Check current Quad Enable bit value. */ 1692 1693 ret = read_cr(nor); ··· 2176 2177 static const struct flash_info *spi_nor_read_id(struct spi_nor *nor) 2177 2178 { 2178 2179 int tmp; 2179 - u8 id[SPI_NOR_MAX_ID_LEN]; 2180 + u8 *id = nor->bouncebuf; 2180 2181 const struct flash_info *info; 2181 2182 2182 2183 tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN); ··· 2392 2393 static int s3an_nor_scan(struct spi_nor *nor) 2393 2394 { 2394 2395 int ret; 2395 - u8 val; 2396 2396 2397 - ret = nor->read_reg(nor, SPINOR_OP_XRDSR, &val, 1); 2397 + ret = nor->read_reg(nor, SPINOR_OP_XRDSR, nor->bouncebuf, 1); 2398 2398 if (ret < 0) { 2399 2399 dev_err(nor->dev, "error %d reading XRDSR\n", (int) ret); 2400 2400 return ret; ··· 2415 2417 * The current addressing mode can be read from the XRDSR register 2416 2418 * and should not be changed, because is a destructive operation. 2417 2419 */ 2418 - if (val & XSR_PAGESIZE) { 2420 + if (nor->bouncebuf[0] & XSR_PAGESIZE) { 2419 2421 /* Flash in Power of 2 mode */ 2420 2422 nor->page_size = (nor->page_size == 264) ? 256 : 512; 2421 2423 nor->mtd.writebufsize = nor->page_size; ··· 4118 4120 nor->reg_proto = SNOR_PROTO_1_1_1; 4119 4121 nor->read_proto = SNOR_PROTO_1_1_1; 4120 4122 nor->write_proto = SNOR_PROTO_1_1_1; 4123 + 4124 + /* 4125 + * We need the bounce buffer early to read/write registers when going 4126 + * through the spi-mem layer (buffers have to be DMA-able). 4127 + */ 4128 + nor->bouncebuf_size = PAGE_SIZE; 4129 + nor->bouncebuf = devm_kmalloc(dev, nor->bouncebuf_size, 4130 + GFP_KERNEL); 4131 + if (!nor->bouncebuf) 4132 + return -ENOMEM; 4121 4133 4122 4134 if (name) 4123 4135 info = spi_nor_match_id(name);
+5 -2
include/linux/mtd/spi-nor.h
··· 344 344 * @mtd: point to a mtd_info structure 345 345 * @lock: the lock for the read/write/erase/lock/unlock operations 346 346 * @dev: point to a spi device, or a spi nor controller device. 347 + * @bouncebuf: bounce buffer used when the buffer passed by the MTD 348 + * layer is not DMA-able 349 + * @bouncebuf_size: size of the bounce buffer 347 350 * @info: spi-nor part JDEC MFR id and other info 348 351 * @page_size: the page size of the SPI NOR 349 352 * @addr_width: number of address bytes ··· 359 356 * @read_proto: the SPI protocol for read operations 360 357 * @write_proto: the SPI protocol for write operations 361 358 * @reg_proto the SPI protocol for read_reg/write_reg/erase operations 362 - * @cmd_buf: used by the write_reg 363 359 * @erase_map: the erase map of the SPI NOR 364 360 * @prepare: [OPTIONAL] do some preparations for the 365 361 * read/write/erase/lock/unlock operations ··· 384 382 struct mtd_info mtd; 385 383 struct mutex lock; 386 384 struct device *dev; 385 + u8 *bouncebuf; 386 + size_t bouncebuf_size; 387 387 const struct flash_info *info; 388 388 u32 page_size; 389 389 u8 addr_width; ··· 398 394 enum spi_nor_protocol reg_proto; 399 395 bool sst_write_second; 400 396 u32 flags; 401 - u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE]; 402 397 struct spi_nor_erase_map erase_map; 403 398 404 399 int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);