Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mtd: sh_flctl: Add power management with QoS request

Adds power management code with fine granularity. Every flash control
command is enclosed by runtime_put()/get()s. To make sure that no
overhead is generated by too frequent power state switches, a quality of
service request is issued.

Signed-off-by: Bastian Hecht <hechtb@gmail.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>

authored by

Bastian Hecht and committed by
David Woodhouse
cfe78194 42d7fbe2

+45 -9
+42 -9
drivers/mtd/nand/sh_flctl.c
··· 26 26 #include <linux/delay.h> 27 27 #include <linux/io.h> 28 28 #include <linux/platform_device.h> 29 + #include <linux/pm_runtime.h> 29 30 #include <linux/slab.h> 30 31 31 32 #include <linux/mtd/mtd.h> ··· 516 515 struct sh_flctl *flctl = mtd_to_flctl(mtd); 517 516 uint32_t read_cmd = 0; 518 517 518 + pm_runtime_get_sync(&flctl->pdev->dev); 519 + 519 520 flctl->read_bytes = 0; 520 521 if (command != NAND_CMD_PAGEPROG) 521 522 flctl->index = 0; ··· 673 670 default: 674 671 break; 675 672 } 676 - return; 673 + goto runtime_exit; 677 674 678 675 read_normal_exit: 679 676 writel(flctl->read_bytes, FLDTCNTR(flctl)); /* set read size */ ··· 681 678 start_translation(flctl); 682 679 read_fiforeg(flctl, flctl->read_bytes, 0); 683 680 wait_completion(flctl); 681 + runtime_exit: 682 + pm_runtime_put_sync(&flctl->pdev->dev); 684 683 return; 685 684 } 686 685 687 686 static void flctl_select_chip(struct mtd_info *mtd, int chipnr) 688 687 { 689 688 struct sh_flctl *flctl = mtd_to_flctl(mtd); 689 + int ret; 690 690 691 691 switch (chipnr) { 692 692 case -1: 693 693 flctl->flcmncr_base &= ~CE0_ENABLE; 694 + 695 + pm_runtime_get_sync(&flctl->pdev->dev); 694 696 writel(flctl->flcmncr_base, FLCMNCR(flctl)); 697 + 698 + if (flctl->qos_request) { 699 + dev_pm_qos_remove_request(&flctl->pm_qos); 700 + flctl->qos_request = 0; 701 + } 702 + 703 + pm_runtime_put_sync(&flctl->pdev->dev); 695 704 break; 696 705 case 0: 697 706 flctl->flcmncr_base |= CE0_ENABLE; 698 - writel(flctl->flcmncr_base, FLCMNCR(flctl)); 699 - if (flctl->holden) 707 + 708 + if (!flctl->qos_request) { 709 + ret = dev_pm_qos_add_request(&flctl->pdev->dev, 710 + &flctl->pm_qos, 100); 711 + if (ret < 0) 712 + dev_err(&flctl->pdev->dev, 713 + "PM QoS request failed: %d\n", ret); 714 + flctl->qos_request = 1; 715 + } 716 + 717 + if (flctl->holden) { 718 + pm_runtime_get_sync(&flctl->pdev->dev); 700 719 writel(HOLDEN, FLHOLDCR(flctl)); 720 + pm_runtime_put_sync(&flctl->pdev->dev); 721 + } 701 722 break; 702 723 default: 703 724 BUG(); ··· 862 835 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 863 836 if (!res) { 864 837 dev_err(&pdev->dev, "failed to get I/O memory\n"); 865 - goto err; 838 + goto err_iomap; 866 839 } 867 840 868 841 flctl->reg = ioremap(res->start, resource_size(res)); 869 842 if (flctl->reg == NULL) { 870 843 dev_err(&pdev->dev, "failed to remap I/O memory\n"); 871 - goto err; 844 + goto err_iomap; 872 845 } 873 846 874 847 platform_set_drvdata(pdev, flctl); ··· 898 871 nand->read_word = flctl_read_word; 899 872 } 900 873 874 + pm_runtime_enable(&pdev->dev); 875 + pm_runtime_resume(&pdev->dev); 876 + 901 877 ret = nand_scan_ident(flctl_mtd, 1, NULL); 902 878 if (ret) 903 - goto err; 879 + goto err_chip; 904 880 905 881 ret = flctl_chip_init_tail(flctl_mtd); 906 882 if (ret) 907 - goto err; 883 + goto err_chip; 908 884 909 885 ret = nand_scan_tail(flctl_mtd); 910 886 if (ret) 911 - goto err; 887 + goto err_chip; 912 888 913 889 mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts); 914 890 915 891 return 0; 916 892 917 - err: 893 + err_chip: 894 + pm_runtime_disable(&pdev->dev); 895 + err_iomap: 918 896 kfree(flctl); 919 897 return ret; 920 898 } ··· 929 897 struct sh_flctl *flctl = platform_get_drvdata(pdev); 930 898 931 899 nand_release(&flctl->mtd); 900 + pm_runtime_disable(&pdev->dev); 932 901 kfree(flctl); 933 902 934 903 return 0;
+3
include/linux/mtd/sh_flctl.h
··· 23 23 #include <linux/mtd/mtd.h> 24 24 #include <linux/mtd/nand.h> 25 25 #include <linux/mtd/partitions.h> 26 + #include <linux/pm_qos.h> 26 27 27 28 /* FLCTL registers */ 28 29 #define FLCMNCR(f) (f->reg + 0x0) ··· 132 131 struct mtd_info mtd; 133 132 struct nand_chip chip; 134 133 struct platform_device *pdev; 134 + struct dev_pm_qos_request pm_qos; 135 135 void __iomem *reg; 136 136 137 137 uint8_t done_buff[2048 + 64]; /* max size 2048 + 64 */ ··· 151 149 unsigned page_size:1; /* NAND page size (0 = 512, 1 = 2048) */ 152 150 unsigned hwecc:1; /* Hardware ECC (0 = disabled, 1 = enabled) */ 153 151 unsigned holden:1; /* Hardware has FLHOLDCR and HOLDEN is set */ 152 + unsigned qos_request:1; /* QoS request to prevent deep power shutdown */ 154 153 }; 155 154 156 155 struct sh_flctl_platform_data {