Commit a3daad82 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'mtd/fixes-for-6.14-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux

Pull mtd fixes from Miquel Raynal:
 "The two most important fixes in this list are probably the SST write
  failure and the Qcom raw NAND controller probe failure which are due
  to some refactoring, otherwise there has been a series of misc fixes
  on the Cadence raw NAND controller driver and especially on the DMA
  side"

* tag 'mtd/fixes-for-6.14-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux:
  mtd: rawnand: cadence: fix unchecked dereference
  mtd: spi-nor: sst: Fix SST write failure
  dt-bindings: mtd: cadence: document required clock-names
  mtd: rawnand: qcom: fix broken config in qcom_param_page_type_exec
  mtd: rawnand: cadence: fix incorrect device in dma_unmap_single
  mtd: rawnand: cadence: use dma_map_resource for sdma address
  mtd: rawnand: cadence: fix error code in cadence_nand_init()
parents 534a2c62 1dbf6027
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -33,6 +33,10 @@ properties:
  clocks:
    maxItems: 1

  clock-names:
    items:
      - const: nf_clk

  dmas:
    maxItems: 1

@@ -51,6 +55,7 @@ required:
  - reg-names
  - interrupts
  - clocks
  - clock-names

unevaluatedProperties: false

@@ -66,7 +71,8 @@ examples:
        #address-cells = <1>;
        #size-cells = <0>;
        interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
        clocks = <&nf_clk>;
        clocks = <&clk>;
        clock-names = "nf_clk";
        cdns,board-delay-ps = <4830>;

        nand@0 {
+33 −11
Original line number Diff line number Diff line
@@ -471,6 +471,8 @@ struct cdns_nand_ctrl {
	struct {
		void __iomem *virt;
		dma_addr_t dma;
		dma_addr_t iova_dma;
		u32 size;
	} io;

	int irq;
@@ -1835,11 +1837,11 @@ static int cadence_nand_slave_dma_transfer(struct cdns_nand_ctrl *cdns_ctrl,
	}

	if (dir == DMA_FROM_DEVICE) {
		src_dma = cdns_ctrl->io.dma;
		src_dma = cdns_ctrl->io.iova_dma;
		dst_dma = buf_dma;
	} else {
		src_dma = buf_dma;
		dst_dma = cdns_ctrl->io.dma;
		dst_dma = cdns_ctrl->io.iova_dma;
	}

	tx = dmaengine_prep_dma_memcpy(cdns_ctrl->dmac, dst_dma, src_dma, len,
@@ -1861,12 +1863,12 @@ static int cadence_nand_slave_dma_transfer(struct cdns_nand_ctrl *cdns_ctrl,
	dma_async_issue_pending(cdns_ctrl->dmac);
	wait_for_completion(&finished);

	dma_unmap_single(cdns_ctrl->dev, buf_dma, len, dir);
	dma_unmap_single(dma_dev->dev, buf_dma, len, dir);

	return 0;

err_unmap:
	dma_unmap_single(cdns_ctrl->dev, buf_dma, len, dir);
	dma_unmap_single(dma_dev->dev, buf_dma, len, dir);

err:
	dev_dbg(cdns_ctrl->dev, "Fall back to CPU I/O\n");
@@ -2869,6 +2871,7 @@ cadence_nand_irq_cleanup(int irqnum, struct cdns_nand_ctrl *cdns_ctrl)
static int cadence_nand_init(struct cdns_nand_ctrl *cdns_ctrl)
{
	dma_cap_mask_t mask;
	struct dma_device *dma_dev = cdns_ctrl->dmac->device;
	int ret;

	cdns_ctrl->cdma_desc = dma_alloc_coherent(cdns_ctrl->dev,
@@ -2904,15 +2907,24 @@ static int cadence_nand_init(struct cdns_nand_ctrl *cdns_ctrl)
	dma_cap_set(DMA_MEMCPY, mask);

	if (cdns_ctrl->caps1->has_dma) {
		cdns_ctrl->dmac = dma_request_channel(mask, NULL, NULL);
		if (!cdns_ctrl->dmac) {
			dev_err(cdns_ctrl->dev,
				"Unable to get a DMA channel\n");
			ret = -EBUSY;
		cdns_ctrl->dmac = dma_request_chan_by_mask(&mask);
		if (IS_ERR(cdns_ctrl->dmac)) {
			ret = dev_err_probe(cdns_ctrl->dev, PTR_ERR(cdns_ctrl->dmac),
					    "%d: Failed to get a DMA channel\n", ret);
			goto disable_irq;
		}
	}

	cdns_ctrl->io.iova_dma = dma_map_resource(dma_dev->dev, cdns_ctrl->io.dma,
						  cdns_ctrl->io.size,
						  DMA_BIDIRECTIONAL, 0);

	ret = dma_mapping_error(dma_dev->dev, cdns_ctrl->io.iova_dma);
	if (ret) {
		dev_err(cdns_ctrl->dev, "Failed to map I/O resource to DMA\n");
		goto dma_release_chnl;
	}

	nand_controller_init(&cdns_ctrl->controller);
	INIT_LIST_HEAD(&cdns_ctrl->chips);

@@ -2923,18 +2935,22 @@ static int cadence_nand_init(struct cdns_nand_ctrl *cdns_ctrl)
	if (ret) {
		dev_err(cdns_ctrl->dev, "Failed to register MTD: %d\n",
			ret);
		goto dma_release_chnl;
		goto unmap_dma_resource;
	}

	kfree(cdns_ctrl->buf);
	cdns_ctrl->buf = kzalloc(cdns_ctrl->buf_size, GFP_KERNEL);
	if (!cdns_ctrl->buf) {
		ret = -ENOMEM;
		goto dma_release_chnl;
		goto unmap_dma_resource;
	}

	return 0;

unmap_dma_resource:
	dma_unmap_resource(dma_dev->dev, cdns_ctrl->io.iova_dma,
			   cdns_ctrl->io.size, DMA_BIDIRECTIONAL, 0);

dma_release_chnl:
	if (cdns_ctrl->dmac)
		dma_release_channel(cdns_ctrl->dmac);
@@ -2956,6 +2972,10 @@ static int cadence_nand_init(struct cdns_nand_ctrl *cdns_ctrl)
static void cadence_nand_remove(struct cdns_nand_ctrl *cdns_ctrl)
{
	cadence_nand_chips_cleanup(cdns_ctrl);
	if (cdns_ctrl->dmac)
		dma_unmap_resource(cdns_ctrl->dmac->device->dev,
				   cdns_ctrl->io.iova_dma, cdns_ctrl->io.size,
				   DMA_BIDIRECTIONAL, 0);
	cadence_nand_irq_cleanup(cdns_ctrl->irq, cdns_ctrl);
	kfree(cdns_ctrl->buf);
	dma_free_coherent(cdns_ctrl->dev, sizeof(struct cadence_nand_cdma_desc),
@@ -3020,7 +3040,9 @@ static int cadence_nand_dt_probe(struct platform_device *ofdev)
	cdns_ctrl->io.virt = devm_platform_get_and_ioremap_resource(ofdev, 1, &res);
	if (IS_ERR(cdns_ctrl->io.virt))
		return PTR_ERR(cdns_ctrl->io.virt);

	cdns_ctrl->io.dma = res->start;
	cdns_ctrl->io.size = resource_size(res);

	dt->clk = devm_clk_get(cdns_ctrl->dev, "nf_clk");
	if (IS_ERR(dt->clk))
+12 −12
Original line number Diff line number Diff line
@@ -1881,18 +1881,18 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_
	nandc->regs->addr0 = 0;
	nandc->regs->addr1 = 0;

	host->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, 0) |
	nandc->regs->cfg0 = cpu_to_le32(FIELD_PREP(CW_PER_PAGE_MASK, 0) |
					FIELD_PREP(UD_SIZE_BYTES_MASK, 512) |
					FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) |
		     FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0);
					FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0));

	host->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) |
	nandc->regs->cfg1 = cpu_to_le32(FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) |
					FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) |
					FIELD_PREP(CS_ACTIVE_BSY, 0) |
					FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) |
					FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) |
					FIELD_PREP(WIDE_FLASH, 0) |
		     FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1);
					FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1));

	if (!nandc->props->qpic_version2)
		nandc->regs->ecc_buf_cfg = cpu_to_le32(ECC_CFG_ECC_DISABLE);
+1 −1
Original line number Diff line number Diff line
@@ -174,7 +174,7 @@ static int sst_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,
	int ret;

	nor->program_opcode = op;
	ret = spi_nor_write_data(nor, to, 1, buf);
	ret = spi_nor_write_data(nor, to, len, buf);
	if (ret < 0)
		return ret;
	WARN(ret != len, "While writing %zu byte written %i bytes\n", len, ret);