Commit 0f710a55 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'libata-5.5-20191226' of git://git.kernel.dk/linux-block

Pull libata fixes from Jens Axboe:
 "Two things in here:

   - First half of a series that fixes ahci_brcm, also marked for
     stable. The other part of the series is going into 5.6 (Florian)

   - sata_nv regression fix that is also marked for stable (Sascha)"

* tag 'libata-5.5-20191226' of git://git.kernel.dk/linux-block:
  ata: ahci_brcm: Add missing clock management during recovery
  ata: ahci_brcm: BCM7425 AHCI requires AHCI_HFLAG_DELAY_ENGINE
  ata: ahci_brcm: Fix AHCI resources management
  ata: libahci_platform: Export again ahci_platform_<en/dis>able_phys()
  libata: Fix retrieving of active qcs
parents 8ae40a69 bf0e5013
Loading
Loading
Loading
Loading
+94 −39
Original line number Diff line number Diff line
@@ -76,8 +76,7 @@ enum brcm_ahci_version {
};

enum brcm_ahci_quirks {
	BRCM_AHCI_QUIRK_NO_NCQ		= BIT(0),
	BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE	= BIT(1),
	BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE	= BIT(0),
};

struct brcm_ahci_priv {
@@ -213,19 +212,12 @@ static void brcm_sata_phys_disable(struct brcm_ahci_priv *priv)
			brcm_sata_phy_disable(priv, i);
}

static u32 brcm_ahci_get_portmask(struct platform_device *pdev,
static u32 brcm_ahci_get_portmask(struct ahci_host_priv *hpriv,
				  struct brcm_ahci_priv *priv)
{
	void __iomem *ahci;
	struct resource *res;
	u32 impl;

	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ahci");
	ahci = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(ahci))
		return 0;

	impl = readl(ahci + HOST_PORTS_IMPL);
	impl = readl(hpriv->mmio + HOST_PORTS_IMPL);

	if (fls(impl) > SATA_TOP_MAX_PHYS)
		dev_warn(priv->dev, "warning: more ports than PHYs (%#x)\n",
@@ -233,9 +225,6 @@ static u32 brcm_ahci_get_portmask(struct platform_device *pdev,
	else if (!impl)
		dev_info(priv->dev, "no ports found\n");

	devm_iounmap(&pdev->dev, ahci);
	devm_release_mem_region(&pdev->dev, res->start, resource_size(res));

	return impl;
}

@@ -285,6 +274,13 @@ static unsigned int brcm_ahci_read_id(struct ata_device *dev,
	/* Perform the SATA PHY reset sequence */
	brcm_sata_phy_disable(priv, ap->port_no);

	/* Reset the SATA clock */
	ahci_platform_disable_clks(hpriv);
	msleep(10);

	ahci_platform_enable_clks(hpriv);
	msleep(10);

	/* Bring the PHY back on */
	brcm_sata_phy_enable(priv, ap->port_no);

@@ -347,11 +343,10 @@ static int brcm_ahci_suspend(struct device *dev)
	struct ata_host *host = dev_get_drvdata(dev);
	struct ahci_host_priv *hpriv = host->private_data;
	struct brcm_ahci_priv *priv = hpriv->plat_data;
	int ret;

	ret = ahci_platform_suspend(dev);
	brcm_sata_phys_disable(priv);
	return ret;

	return ahci_platform_suspend(dev);
}

static int brcm_ahci_resume(struct device *dev)
@@ -359,11 +354,44 @@ static int brcm_ahci_resume(struct device *dev)
	struct ata_host *host = dev_get_drvdata(dev);
	struct ahci_host_priv *hpriv = host->private_data;
	struct brcm_ahci_priv *priv = hpriv->plat_data;
	int ret;

	/* Make sure clocks are turned on before re-configuration */
	ret = ahci_platform_enable_clks(hpriv);
	if (ret)
		return ret;

	brcm_sata_init(priv);
	brcm_sata_phys_enable(priv);
	brcm_sata_alpm_init(hpriv);
	return ahci_platform_resume(dev);

	/* Since we had to enable clocks earlier on, we cannot use
	 * ahci_platform_resume() as-is since a second call to
	 * ahci_platform_enable_resources() would bump up the resources
	 * (regulators, clocks, PHYs) count artificially so we copy the part
	 * after ahci_platform_enable_resources().
	 */
	ret = ahci_platform_enable_phys(hpriv);
	if (ret)
		goto out_disable_phys;

	ret = ahci_platform_resume_host(dev);
	if (ret)
		goto out_disable_platform_phys;

	/* We resumed so update PM runtime state */
	pm_runtime_disable(dev);
	pm_runtime_set_active(dev);
	pm_runtime_enable(dev);

	return 0;

out_disable_platform_phys:
	ahci_platform_disable_phys(hpriv);
out_disable_phys:
	brcm_sata_phys_disable(priv);
	ahci_platform_disable_clks(hpriv);
	return ret;
}
#endif

@@ -410,44 +438,71 @@ static int brcm_ahci_probe(struct platform_device *pdev)
	if (!IS_ERR_OR_NULL(priv->rcdev))
		reset_control_deassert(priv->rcdev);

	if ((priv->version == BRCM_SATA_BCM7425) ||
		(priv->version == BRCM_SATA_NSP)) {
		priv->quirks |= BRCM_AHCI_QUIRK_NO_NCQ;
	hpriv = ahci_platform_get_resources(pdev, 0);
	if (IS_ERR(hpriv)) {
		ret = PTR_ERR(hpriv);
		goto out_reset;
	}

	hpriv->plat_data = priv;
	hpriv->flags = AHCI_HFLAG_WAKE_BEFORE_STOP | AHCI_HFLAG_NO_WRITE_TO_RO;

	switch (priv->version) {
	case BRCM_SATA_BCM7425:
		hpriv->flags |= AHCI_HFLAG_DELAY_ENGINE;
		/* fall through */
	case BRCM_SATA_NSP:
		hpriv->flags |= AHCI_HFLAG_NO_NCQ;
		priv->quirks |= BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE;
		break;
	default:
		break;
	}

	ret = ahci_platform_enable_clks(hpriv);
	if (ret)
		goto out_reset;

	/* Must be first so as to configure endianness including that
	 * of the standard AHCI register space.
	 */
	brcm_sata_init(priv);

	priv->port_mask = brcm_ahci_get_portmask(pdev, priv);
	if (!priv->port_mask)
		return -ENODEV;
	/* Initializes priv->port_mask which is used below */
	priv->port_mask = brcm_ahci_get_portmask(hpriv, priv);
	if (!priv->port_mask) {
		ret = -ENODEV;
		goto out_disable_clks;
	}

	/* Must be done before ahci_platform_enable_phys() */
	brcm_sata_phys_enable(priv);

	hpriv = ahci_platform_get_resources(pdev, 0);
	if (IS_ERR(hpriv))
		return PTR_ERR(hpriv);
	hpriv->plat_data = priv;
	hpriv->flags = AHCI_HFLAG_WAKE_BEFORE_STOP;

	brcm_sata_alpm_init(hpriv);

	ret = ahci_platform_enable_resources(hpriv);
	ret = ahci_platform_enable_phys(hpriv);
	if (ret)
		return ret;

	if (priv->quirks & BRCM_AHCI_QUIRK_NO_NCQ)
		hpriv->flags |= AHCI_HFLAG_NO_NCQ;
	hpriv->flags |= AHCI_HFLAG_NO_WRITE_TO_RO;
		goto out_disable_phys;

	ret = ahci_platform_init_host(pdev, hpriv, &ahci_brcm_port_info,
				      &ahci_platform_sht);
	if (ret)
		return ret;
		goto out_disable_platform_phys;

	dev_info(dev, "Broadcom AHCI SATA3 registered\n");

	return 0;

out_disable_platform_phys:
	ahci_platform_disable_phys(hpriv);
out_disable_phys:
	brcm_sata_phys_disable(priv);
out_disable_clks:
	ahci_platform_disable_clks(hpriv);
out_reset:
	if (!IS_ERR_OR_NULL(priv->rcdev))
		reset_control_assert(priv->rcdev);
	return ret;
}

static int brcm_ahci_remove(struct platform_device *pdev)
@@ -457,12 +512,12 @@ static int brcm_ahci_remove(struct platform_device *pdev)
	struct brcm_ahci_priv *priv = hpriv->plat_data;
	int ret;

	brcm_sata_phys_disable(priv);

	ret = ata_platform_remove_one(pdev);
	if (ret)
		return ret;

	brcm_sata_phys_disable(priv);

	return 0;
}

+4 −2
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ EXPORT_SYMBOL_GPL(ahci_platform_ops);
 * RETURNS:
 * 0 on success otherwise a negative error code
 */
static int ahci_platform_enable_phys(struct ahci_host_priv *hpriv)
int ahci_platform_enable_phys(struct ahci_host_priv *hpriv)
{
	int rc, i;

@@ -74,6 +74,7 @@ disable_phys:
	}
	return rc;
}
EXPORT_SYMBOL_GPL(ahci_platform_enable_phys);

/**
 * ahci_platform_disable_phys - Disable PHYs
@@ -81,7 +82,7 @@ disable_phys:
 *
 * This function disables all PHYs found in hpriv->phys.
 */
static void ahci_platform_disable_phys(struct ahci_host_priv *hpriv)
void ahci_platform_disable_phys(struct ahci_host_priv *hpriv)
{
	int i;

@@ -90,6 +91,7 @@ static void ahci_platform_disable_phys(struct ahci_host_priv *hpriv)
		phy_exit(hpriv->phys[i]);
	}
}
EXPORT_SYMBOL_GPL(ahci_platform_disable_phys);

/**
 * ahci_platform_enable_clks - Enable platform clocks
+24 −0
Original line number Diff line number Diff line
@@ -5328,6 +5328,30 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
	}
}

/**
 *	ata_qc_get_active - get bitmask of active qcs
 *	@ap: port in question
 *
 *	LOCKING:
 *	spin_lock_irqsave(host lock)
 *
 *	RETURNS:
 *	Bitmask of active qcs
 */
u64 ata_qc_get_active(struct ata_port *ap)
{
	u64 qc_active = ap->qc_active;

	/* ATA_TAG_INTERNAL is sent to hw as tag 0 */
	if (qc_active & (1ULL << ATA_TAG_INTERNAL)) {
		qc_active |= (1 << 0);
		qc_active &= ~(1ULL << ATA_TAG_INTERNAL);
	}

	return qc_active;
}
EXPORT_SYMBOL_GPL(ata_qc_get_active);

/**
 *	ata_qc_complete_multiple - Complete multiple qcs successfully
 *	@ap: port in question
+1 −1
Original line number Diff line number Diff line
@@ -1280,7 +1280,7 @@ static void sata_fsl_host_intr(struct ata_port *ap)
				     i, ioread32(hcr_base + CC),
				     ioread32(hcr_base + CA));
		}
		ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
		ata_qc_complete_multiple(ap, ata_qc_get_active(ap) ^ done_mask);
		return;

	} else if ((ap->qc_active & (1ULL << ATA_TAG_INTERNAL))) {
+1 −1
Original line number Diff line number Diff line
@@ -2829,7 +2829,7 @@ static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp
	}

	if (work_done) {
		ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
		ata_qc_complete_multiple(ap, ata_qc_get_active(ap) ^ done_mask);

		/* Update the software queue position index in hardware */
		writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) |
Loading