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

Merge tag 'cxl-fixes-for-6.2-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl

Pull cxl fixes from Dan Williams:
 "A couple of fixes for bugs introduced during the merge window. One is
  a regression, the other was a bug in the CXL AER handler:

   - Fix a crash regression due to module load order of cxl_pmem.ko

   - Fix wrong register offset read in CXL AER handling path"

* tag 'cxl-fixes-for-6.2-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl:
  cxl/pmem: Fix nvdimm unregistration when cxl_pmem driver is absent
  cxl: fix cxl_report_and_clear() RAS UE addr mis-assignment
parents 95e7a450 19398821
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -736,4 +736,3 @@ module_exit(cxl_acpi_exit);
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(CXL);
MODULE_IMPORT_NS(ACPI);
MODULE_SOFTDEP("pre: cxl_pmem");
+4 −38
Original line number Diff line number Diff line
@@ -227,34 +227,16 @@ static struct cxl_nvdimm *cxl_nvdimm_alloc(struct cxl_nvdimm_bridge *cxl_nvb,
	return cxl_nvd;
}

static void cxl_nvd_unregister(void *_cxl_nvd)
static void cxlmd_release_nvdimm(void *_cxlmd)
{
	struct cxl_nvdimm *cxl_nvd = _cxl_nvd;
	struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
	struct cxl_memdev *cxlmd = _cxlmd;
	struct cxl_nvdimm *cxl_nvd = cxlmd->cxl_nvd;
	struct cxl_nvdimm_bridge *cxl_nvb = cxlmd->cxl_nvb;

	/*
	 * Either the bridge is in ->remove() context under the device_lock(),
	 * or cxlmd_release_nvdimm() is cancelling the bridge's release action
	 * for @cxl_nvd and doing it itself (while manually holding the bridge
	 * lock).
	 */
	device_lock_assert(&cxl_nvb->dev);
	cxl_nvd->cxlmd = NULL;
	cxlmd->cxl_nvd = NULL;
	cxlmd->cxl_nvb = NULL;
	device_unregister(&cxl_nvd->dev);
}

static void cxlmd_release_nvdimm(void *_cxlmd)
{
	struct cxl_memdev *cxlmd = _cxlmd;
	struct cxl_nvdimm_bridge *cxl_nvb = cxlmd->cxl_nvb;

	device_lock(&cxl_nvb->dev);
	if (cxlmd->cxl_nvd)
		devm_release_action(&cxl_nvb->dev, cxl_nvd_unregister,
				    cxlmd->cxl_nvd);
	device_unlock(&cxl_nvb->dev);
	put_device(&cxl_nvb->dev);
}

@@ -293,22 +275,6 @@ int devm_cxl_add_nvdimm(struct cxl_memdev *cxlmd)

	dev_dbg(&cxlmd->dev, "register %s\n", dev_name(dev));

	/*
	 * The two actions below arrange for @cxl_nvd to be deleted when either
	 * the top-level PMEM bridge goes down, or the endpoint device goes
	 * through ->remove().
	 */
	device_lock(&cxl_nvb->dev);
	if (cxl_nvb->dev.driver)
		rc = devm_add_action_or_reset(&cxl_nvb->dev, cxl_nvd_unregister,
					      cxl_nvd);
	else
		rc = -ENXIO;
	device_unlock(&cxl_nvb->dev);

	if (rc)
		goto err_alloc;

	/* @cxlmd carries a reference on @cxl_nvb until cxlmd_release_nvdimm */
	return devm_add_action_or_reset(&cxlmd->dev, cxlmd_release_nvdimm, cxlmd);

+5 −2
Original line number Diff line number Diff line
@@ -554,8 +554,11 @@ static bool cxl_report_and_clear(struct cxl_dev_state *cxlds)

	/* If multiple errors, log header points to first error from ctrl reg */
	if (hweight32(status) > 1) {
		addr = cxlds->regs.ras + CXL_RAS_CAP_CONTROL_OFFSET;
		fe = BIT(FIELD_GET(CXL_RAS_CAP_CONTROL_FE_MASK, readl(addr)));
		void __iomem *rcc_addr =
			cxlds->regs.ras + CXL_RAS_CAP_CONTROL_OFFSET;

		fe = BIT(FIELD_GET(CXL_RAS_CAP_CONTROL_FE_MASK,
				   readl(rcc_addr)));
	} else {
		fe = status;
	}
+24 −0
Original line number Diff line number Diff line
@@ -225,11 +225,35 @@ static int cxl_pmem_ctl(struct nvdimm_bus_descriptor *nd_desc,
	return cxl_pmem_nvdimm_ctl(nvdimm, cmd, buf, buf_len);
}

static int detach_nvdimm(struct device *dev, void *data)
{
	struct cxl_nvdimm *cxl_nvd;
	bool release = false;

	if (!is_cxl_nvdimm(dev))
		return 0;

	device_lock(dev);
	if (!dev->driver)
		goto out;

	cxl_nvd = to_cxl_nvdimm(dev);
	if (cxl_nvd->cxlmd && cxl_nvd->cxlmd->cxl_nvb == data)
		release = true;
out:
	device_unlock(dev);
	if (release)
		device_release_driver(dev);
	return 0;
}

static void unregister_nvdimm_bus(void *_cxl_nvb)
{
	struct cxl_nvdimm_bridge *cxl_nvb = _cxl_nvb;
	struct nvdimm_bus *nvdimm_bus = cxl_nvb->nvdimm_bus;

	bus_for_each_dev(&cxl_bus_type, NULL, cxl_nvb, detach_nvdimm);

	cxl_nvb->nvdimm_bus = NULL;
	nvdimm_bus_unregister(nvdimm_bus);
}