Skip to content

Commit 3e9c49d

Browse files
ausyskinmiquelraynal
authored andcommitted
mtd: intel-dg: wake card on operations
The Intel DG cards do not have separate power control for persistent memory. The memory is available when the whole card is awake. Enable runtime PM in mtd driver to notify parent graphics driver that whole card should be kept awake while nvm operations are performed through this driver. Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
1 parent 9d4d01a commit 3e9c49d

1 file changed

Lines changed: 62 additions & 12 deletions

File tree

drivers/mtd/devices/mtd_intel_dg.c

Lines changed: 62 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,18 @@
1515
#include <linux/module.h>
1616
#include <linux/mtd/mtd.h>
1717
#include <linux/mtd/partitions.h>
18+
#include <linux/pm_runtime.h>
1819
#include <linux/string.h>
1920
#include <linux/slab.h>
2021
#include <linux/sizes.h>
2122
#include <linux/types.h>
2223

24+
#define INTEL_DG_NVM_RPM_TIMEOUT_MS 500
25+
2326
struct intel_dg_nvm {
2427
struct kref refcnt;
2528
struct mtd_info mtd;
29+
struct device *dev;
2630
struct mutex lock; /* region access lock */
2731
void __iomem *base;
2832
void __iomem *base2;
@@ -421,6 +425,8 @@ static int intel_dg_nvm_init(struct intel_dg_nvm *nvm, struct device *device,
421425
unsigned int i, n;
422426
int ret;
423427

428+
nvm->dev = device;
429+
424430
/* clean error register, previous errors are ignored */
425431
idg_nvm_error(nvm);
426432

@@ -498,6 +504,7 @@ static int intel_dg_mtd_erase(struct mtd_info *mtd, struct erase_info *info)
498504
size_t len;
499505
u8 region;
500506
u64 addr;
507+
int ret;
501508

502509
if (WARN_ON(!nvm))
503510
return -EINVAL;
@@ -512,20 +519,29 @@ static int intel_dg_mtd_erase(struct mtd_info *mtd, struct erase_info *info)
512519
total_len = info->len;
513520
addr = info->addr;
514521

522+
ret = pm_runtime_resume_and_get(nvm->dev);
523+
if (ret < 0) {
524+
dev_err(&mtd->dev, "rpm: get failed %d\n", ret);
525+
return ret;
526+
}
527+
528+
ret = 0;
515529
guard(mutex)(&nvm->lock);
516530

517531
while (total_len > 0) {
518532
if (!IS_ALIGNED(addr, SZ_4K) || !IS_ALIGNED(total_len, SZ_4K)) {
519533
dev_err(&mtd->dev, "unaligned erase %llx %zx\n", addr, total_len);
520534
info->fail_addr = addr;
521-
return -ERANGE;
535+
ret = -ERANGE;
536+
break;
522537
}
523538

524539
idx = idg_nvm_get_region(nvm, addr);
525540
if (idx >= nvm->nregions) {
526541
dev_err(&mtd->dev, "out of range");
527542
info->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
528-
return -ERANGE;
543+
ret = -ERANGE;
544+
break;
529545
}
530546

531547
from = addr - nvm->regions[idx].offset;
@@ -541,14 +557,16 @@ static int intel_dg_mtd_erase(struct mtd_info *mtd, struct erase_info *info)
541557
if (bytes < 0) {
542558
dev_dbg(&mtd->dev, "erase failed with %zd\n", bytes);
543559
info->fail_addr += nvm->regions[idx].offset;
544-
return bytes;
560+
ret = bytes;
561+
break;
545562
}
546563

547564
addr += len;
548565
total_len -= len;
549566
}
550567

551-
return 0;
568+
pm_runtime_put_autosuspend(nvm->dev);
569+
return ret;
552570
}
553571

554572
static int intel_dg_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
@@ -577,17 +595,24 @@ static int intel_dg_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
577595
if (len > nvm->regions[idx].size - from)
578596
len = nvm->regions[idx].size - from;
579597

598+
ret = pm_runtime_resume_and_get(nvm->dev);
599+
if (ret < 0) {
600+
dev_err(&mtd->dev, "rpm: get failed %zd\n", ret);
601+
return ret;
602+
}
603+
580604
guard(mutex)(&nvm->lock);
581605

582606
ret = idg_read(nvm, region, from, len, buf);
583607
if (ret < 0) {
584608
dev_dbg(&mtd->dev, "read failed with %zd\n", ret);
585-
return ret;
609+
} else {
610+
*retlen = ret;
611+
ret = 0;
586612
}
587613

588-
*retlen = ret;
589-
590-
return 0;
614+
pm_runtime_put_autosuspend(nvm->dev);
615+
return ret;
591616
}
592617

593618
static int intel_dg_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
@@ -616,17 +641,24 @@ static int intel_dg_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
616641
if (len > nvm->regions[idx].size - to)
617642
len = nvm->regions[idx].size - to;
618643

644+
ret = pm_runtime_resume_and_get(nvm->dev);
645+
if (ret < 0) {
646+
dev_err(&mtd->dev, "rpm: get failed %zd\n", ret);
647+
return ret;
648+
}
649+
619650
guard(mutex)(&nvm->lock);
620651

621652
ret = idg_write(nvm, region, to, len, buf);
622653
if (ret < 0) {
623654
dev_dbg(&mtd->dev, "write failed with %zd\n", ret);
624-
return ret;
655+
} else {
656+
*retlen = ret;
657+
ret = 0;
625658
}
626659

627-
*retlen = ret;
628-
629-
return 0;
660+
pm_runtime_put_autosuspend(nvm->dev);
661+
return ret;
630662
}
631663

632664
static void intel_dg_nvm_release(struct kref *kref)
@@ -753,6 +785,21 @@ static int intel_dg_mtd_probe(struct auxiliary_device *aux_dev,
753785
}
754786
nvm->nregions = n; /* in case where kasprintf fail */
755787

788+
ret = devm_pm_runtime_enable(device);
789+
if (ret < 0) {
790+
dev_err(device, "rpm: enable failed %d\n", ret);
791+
goto err_norpm;
792+
}
793+
794+
pm_runtime_set_autosuspend_delay(device, INTEL_DG_NVM_RPM_TIMEOUT_MS);
795+
pm_runtime_use_autosuspend(device);
796+
797+
ret = pm_runtime_resume_and_get(device);
798+
if (ret < 0) {
799+
dev_err(device, "rpm: get failed %d\n", ret);
800+
goto err_norpm;
801+
}
802+
756803
nvm->base = devm_ioremap_resource(device, &invm->bar);
757804
if (IS_ERR(nvm->base)) {
758805
ret = PTR_ERR(nvm->base);
@@ -781,9 +828,12 @@ static int intel_dg_mtd_probe(struct auxiliary_device *aux_dev,
781828

782829
dev_set_drvdata(&aux_dev->dev, nvm);
783830

831+
pm_runtime_put(device);
784832
return 0;
785833

786834
err:
835+
pm_runtime_put(device);
836+
err_norpm:
787837
kref_put(&nvm->refcnt, intel_dg_nvm_release);
788838
return ret;
789839
}

0 commit comments

Comments
 (0)