mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
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: Rodrigo Vivi <rodrigo.vivi@intel.com> Acked-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: Reuven Abliyev <reuven.abliyev@intel.com> Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com> Link: https://lore.kernel.org/r/20250617145159.3803852-9-alexander.usyskin@intel.com Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
This commit is contained in:
parent
87e1ebbafb
commit
a1c940cbf5
|
|
@ -14,7 +14,15 @@
|
||||||
#include "xe_sriov.h"
|
#include "xe_sriov.h"
|
||||||
|
|
||||||
#define GEN12_GUNIT_NVM_BASE 0x00102040
|
#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_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)
|
#define HECI_FW_STATUS_2_NVM_ACCESS_MODE BIT(3)
|
||||||
|
|
||||||
static const struct intel_dg_nvm_region regions[INTEL_DG_NVM_REGIONS] = {
|
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(>->mmio, XE_REG(GEN12_CNTL_PROTECTED_NVM_REG)) &
|
||||||
|
NVM_NON_POSTED_ERASE_CHICKEN_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
static bool xe_nvm_writable_override(struct xe_device *xe)
|
static bool xe_nvm_writable_override(struct xe_device *xe)
|
||||||
{
|
{
|
||||||
struct xe_gt *gt = xe_root_mmio_gt(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 = xe->nvm;
|
||||||
|
|
||||||
nvm->writable_override = xe_nvm_writable_override(xe);
|
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.parent = &pdev->resource[0];
|
||||||
nvm->bar.start = GEN12_GUNIT_NVM_BASE + pdev->resource[0].start;
|
nvm->bar.start = GEN12_GUNIT_NVM_BASE + pdev->resource[0].start;
|
||||||
nvm->bar.end = nvm->bar.start + GEN12_GUNIT_NVM_SIZE - 1;
|
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->bar.desc = IORES_DESC_NONE;
|
||||||
nvm->regions = regions;
|
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 = &nvm->aux_dev;
|
||||||
|
|
||||||
aux_dev->name = "nvm";
|
aux_dev->name = "nvm";
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,9 @@ struct intel_dg_nvm {
|
||||||
struct mtd_info mtd;
|
struct mtd_info mtd;
|
||||||
struct mutex lock; /* region access lock */
|
struct mutex lock; /* region access lock */
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
|
void __iomem *base2;
|
||||||
|
bool non_posted_erase;
|
||||||
|
|
||||||
size_t size;
|
size_t size;
|
||||||
unsigned int nregions;
|
unsigned int nregions;
|
||||||
struct {
|
struct {
|
||||||
|
|
@ -41,6 +44,7 @@ struct intel_dg_nvm {
|
||||||
#define NVM_VALSIG_REG 0x00000010
|
#define NVM_VALSIG_REG 0x00000010
|
||||||
#define NVM_ADDRESS_REG 0x00000040
|
#define NVM_ADDRESS_REG 0x00000040
|
||||||
#define NVM_REGION_ID_REG 0x00000044
|
#define NVM_REGION_ID_REG 0x00000044
|
||||||
|
#define NVM_DEBUG_REG 0x00000000
|
||||||
/*
|
/*
|
||||||
* [15:0]-Erase size = 0x0010 4K 0x0080 32K 0x0100 64K
|
* [15:0]-Erase size = 0x0010 4K 0x0080 32K 0x0100 64K
|
||||||
* [23:16]-Reserved
|
* [23:16]-Reserved
|
||||||
|
|
@ -72,6 +76,9 @@ struct intel_dg_nvm {
|
||||||
#define NVM_FREG_ADDR_SHIFT 12
|
#define NVM_FREG_ADDR_SHIFT 12
|
||||||
#define NVM_FREG_MIN_REGION_SIZE 0xFFF
|
#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)
|
static inline void idg_nvm_set_region_id(struct intel_dg_nvm *nvm, u8 region)
|
||||||
{
|
{
|
||||||
iowrite32((u32)region, nvm->base + NVM_REGION_ID_REG);
|
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
|
static ssize_t
|
||||||
idg_erase(struct intel_dg_nvm *nvm, u8 region, loff_t from, u64 len, u64 *fail_addr)
|
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;
|
void __iomem *base = nvm->base;
|
||||||
const u32 block = 0x10;
|
const u32 block = 0x10;
|
||||||
|
u32 iter = 0;
|
||||||
|
u32 reg;
|
||||||
u64 i;
|
u64 i;
|
||||||
|
|
||||||
for (i = 0; i < len; i += SZ_4K) {
|
for (i = 0; i < len; i += SZ_4K) {
|
||||||
iowrite32(from + i, base + NVM_ADDRESS_REG);
|
iowrite32(from + i, base + NVM_ADDRESS_REG);
|
||||||
iowrite32(region << 24 | block, base + NVM_ERASE_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
|
/* Since the writes are via sgunit
|
||||||
* we cannot do back to back erases.
|
* 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;
|
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;
|
u32 access_map = 0;
|
||||||
unsigned int i, n;
|
unsigned int i, n;
|
||||||
|
|
@ -448,7 +475,10 @@ static int intel_dg_nvm_init(struct intel_dg_nvm *nvm, struct device *device)
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nvm->non_posted_erase = non_posted_erase;
|
||||||
|
|
||||||
dev_dbg(device, "Registered %d regions\n", n);
|
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
|
/* Need to add 1 to the amount of memory
|
||||||
* so it is reported as an even block
|
* 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;
|
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) {
|
if (ret < 0) {
|
||||||
dev_err(device, "cannot initialize nvm %d\n", ret);
|
dev_err(device, "cannot initialize nvm %d\n", ret);
|
||||||
goto err;
|
goto err;
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,9 @@ struct intel_dg_nvm_region {
|
||||||
struct intel_dg_nvm_dev {
|
struct intel_dg_nvm_dev {
|
||||||
struct auxiliary_device aux_dev;
|
struct auxiliary_device aux_dev;
|
||||||
bool writable_override;
|
bool writable_override;
|
||||||
|
bool non_posted_erase;
|
||||||
struct resource bar;
|
struct resource bar;
|
||||||
|
struct resource bar2;
|
||||||
const struct intel_dg_nvm_region *regions;
|
const struct intel_dg_nvm_region *regions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user