Unverified Commit a1c940cb authored by Reuven Abliyev's avatar Reuven Abliyev Committed by Rodrigo Vivi
Browse files

drm/xe/nvm: add support for non-posted erase



Erase command is slow on discrete graphics storage
and may overshot PCI completion timeout.
BMG introduces the ability to have non-posted erase.
Add driver support for non-posted erase with polling
for erase completion.

Reviewed-by: default avatarRodrigo Vivi <rodrigo.vivi@intel.com>
Acked-by: default avatarRodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: default avatarReuven Abliyev <reuven.abliyev@intel.com>
Signed-off-by: default avatarAlexander Usyskin <alexander.usyskin@intel.com>
Link: https://lore.kernel.org/r/20250617145159.3803852-9-alexander.usyskin@intel.com


Signed-off-by: default avatarRodrigo Vivi <rodrigo.vivi@intel.com>
parent 87e1ebba
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -14,7 +14,15 @@
#include "xe_sriov.h"

#define GEN12_GUNIT_NVM_BASE 0x00102040
#define GEN12_DEBUG_NVM_BASE 0x00101018

#define GEN12_CNTL_PROTECTED_NVM_REG 0x0010100C

#define GEN12_GUNIT_NVM_SIZE 0x80
#define GEN12_DEBUG_NVM_SIZE 0x4

#define NVM_NON_POSTED_ERASE_CHICKEN_BIT BIT(13)

#define HECI_FW_STATUS_2_NVM_ACCESS_MODE BIT(3)

static const struct intel_dg_nvm_region regions[INTEL_DG_NVM_REGIONS] = {
@@ -29,6 +37,16 @@ static void xe_nvm_release_dev(struct device *dev)
{
}

static bool xe_nvm_non_posted_erase(struct xe_device *xe)
{
	struct xe_gt *gt = xe_root_mmio_gt(xe);

	if (xe->info.platform != XE_BATTLEMAGE)
		return false;
	return !(xe_mmio_read32(&gt->mmio, XE_REG(GEN12_CNTL_PROTECTED_NVM_REG)) &
		 NVM_NON_POSTED_ERASE_CHICKEN_BIT);
}

static bool xe_nvm_writable_override(struct xe_device *xe)
{
	struct xe_gt *gt = xe_root_mmio_gt(xe);
@@ -86,6 +104,7 @@ int xe_nvm_init(struct xe_device *xe)
	nvm = xe->nvm;

	nvm->writable_override = xe_nvm_writable_override(xe);
	nvm->non_posted_erase = xe_nvm_non_posted_erase(xe);
	nvm->bar.parent = &pdev->resource[0];
	nvm->bar.start = GEN12_GUNIT_NVM_BASE + pdev->resource[0].start;
	nvm->bar.end = nvm->bar.start + GEN12_GUNIT_NVM_SIZE - 1;
@@ -93,6 +112,12 @@ int xe_nvm_init(struct xe_device *xe)
	nvm->bar.desc = IORES_DESC_NONE;
	nvm->regions = regions;

	nvm->bar2.parent = &pdev->resource[0];
	nvm->bar2.start = GEN12_DEBUG_NVM_BASE + pdev->resource[0].start;
	nvm->bar2.end = nvm->bar2.start + GEN12_DEBUG_NVM_SIZE - 1;
	nvm->bar2.flags = IORESOURCE_MEM;
	nvm->bar2.desc = IORES_DESC_NONE;

	aux_dev = &nvm->aux_dev;

	aux_dev->name = "nvm";
+40 −2
Original line number Diff line number Diff line
@@ -25,6 +25,9 @@ struct intel_dg_nvm {
	struct mtd_info mtd;
	struct mutex lock; /* region access lock */
	void __iomem *base;
	void __iomem *base2;
	bool non_posted_erase;

	size_t size;
	unsigned int nregions;
	struct {
@@ -41,6 +44,7 @@ struct intel_dg_nvm {
#define NVM_VALSIG_REG        0x00000010
#define NVM_ADDRESS_REG       0x00000040
#define NVM_REGION_ID_REG     0x00000044
#define NVM_DEBUG_REG         0x00000000
/*
 * [15:0]-Erase size = 0x0010 4K 0x0080 32K 0x0100 64K
 * [23:16]-Reserved
@@ -72,6 +76,9 @@ struct intel_dg_nvm {
#define NVM_FREG_ADDR_SHIFT 12
#define NVM_FREG_MIN_REGION_SIZE 0xFFF

#define NVM_NON_POSTED_ERASE_DONE BIT(23)
#define NVM_NON_POSTED_ERASE_DONE_ITER 3000

static inline void idg_nvm_set_region_id(struct intel_dg_nvm *nvm, u8 region)
{
	iowrite32((u32)region, nvm->base + NVM_REGION_ID_REG);
@@ -373,13 +380,32 @@ static ssize_t idg_read(struct intel_dg_nvm *nvm, u8 region,
static ssize_t
idg_erase(struct intel_dg_nvm *nvm, u8 region, loff_t from, u64 len, u64 *fail_addr)
{
	void __iomem *base2 = nvm->base2;
	void __iomem *base = nvm->base;
	const u32 block = 0x10;
	u32 iter = 0;
	u32 reg;
	u64 i;

	for (i = 0; i < len; i += SZ_4K) {
		iowrite32(from + i, base + NVM_ADDRESS_REG);
		iowrite32(region << 24 | block, base + NVM_ERASE_REG);
		if (nvm->non_posted_erase) {
			/* Wait for Erase Done */
			reg = ioread32(base2 + NVM_DEBUG_REG);
			while (!(reg & NVM_NON_POSTED_ERASE_DONE) &&
			       ++iter < NVM_NON_POSTED_ERASE_DONE_ITER) {
				msleep(10);
				reg = ioread32(base2 + NVM_DEBUG_REG);
			}
			if (reg & NVM_NON_POSTED_ERASE_DONE) {
				/* Clear Erase Done */
				iowrite32(reg, base2 + NVM_DEBUG_REG);
			} else {
				*fail_addr = from + i;
				return -ETIME;
			}
		}
		/* Since the writes are via sgunit
		 * we cannot do back to back erases.
		 */
@@ -388,7 +414,8 @@ idg_erase(struct intel_dg_nvm *nvm, u8 region, loff_t from, u64 len, u64 *fail_a
	return len;
}

static int intel_dg_nvm_init(struct intel_dg_nvm *nvm, struct device *device)
static int intel_dg_nvm_init(struct intel_dg_nvm *nvm, struct device *device,
			     bool non_posted_erase)
{
	u32 access_map = 0;
	unsigned int i, n;
@@ -448,7 +475,10 @@ static int intel_dg_nvm_init(struct intel_dg_nvm *nvm, struct device *device)
			n++;
	}

	nvm->non_posted_erase = non_posted_erase;

	dev_dbg(device, "Registered %d regions\n", n);
	dev_dbg(device, "Non posted erase %d\n", nvm->non_posted_erase);

	/* Need to add 1 to the amount of memory
	 * so it is reported as an even block
@@ -729,7 +759,15 @@ static int intel_dg_mtd_probe(struct auxiliary_device *aux_dev,
		goto err;
	}

	ret = intel_dg_nvm_init(nvm, device);
	if (invm->non_posted_erase) {
		nvm->base2 = devm_ioremap_resource(device, &invm->bar2);
		if (IS_ERR(nvm->base2)) {
			ret = PTR_ERR(nvm->base2);
			goto err;
		}
	}

	ret = intel_dg_nvm_init(nvm, device, invm->non_posted_erase);
	if (ret < 0) {
		dev_err(device, "cannot initialize nvm %d\n", ret);
		goto err;
+2 −0
Original line number Diff line number Diff line
@@ -20,7 +20,9 @@ struct intel_dg_nvm_region {
struct intel_dg_nvm_dev {
	struct auxiliary_device aux_dev;
	bool writable_override;
	bool non_posted_erase;
	struct resource bar;
	struct resource bar2;
	const struct intel_dg_nvm_region *regions;
};