aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Boyd <stephen.boyd@linaro.org>2016-08-02 17:04:22 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-08-02 19:35:09 -0400
commit9ccf98119821defe66ee2ee21f8a11071f63fa65 (patch)
tree499eeca65b37cd89c76cd497fe8fb01ffaceea65
parenta23216a2f1f8a30a3b6588c743681651e4a6aa94 (diff)
firmware: consolidate kmap/read/write logic
Some systems are memory constrained but they need to load very large firmwares. The firmware subsystem allows drivers to request this firmware be loaded from the filesystem, but this requires that the entire firmware be loaded into kernel memory first before it's provided to the driver. This can lead to a situation where we map the firmware twice, once to load the firmware into kernel memory and once to copy the firmware into the final resting place. This design creates needless memory pressure and delays loading because we have to copy from kernel memory to somewhere else. This patch sets adds support to the request firmware API to load the firmware directly into a pre-allocated buffer, skipping the intermediate copying step and alleviating memory pressure during firmware loading. The drawback is that we can't use the firmware caching feature because the memory for the firmware cache is not managed by the firmware layer. This patch (of 3): We use similar structured code to read and write the kmapped firmware pages. The only difference is read copies from the kmap region and write copies to it. Consolidate this into one function to reduce duplication. Link: http://lkml.kernel.org/r/20160607164741.31849-2-stephen.boyd@linaro.org Signed-off-by: Stephen Boyd <stephen.boyd@linaro.org> Cc: Vikram Mulukutla <markivx@codeaurora.org> Cc: Mimi Zohar <zohar@linux.vnet.ibm.com> Cc: Mark Brown <broonie@kernel.org> Cc: Ming Lei <ming.lei@canonical.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/base/firmware_class.c57
1 files changed, 26 insertions, 31 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 773fc3099769..01d55723d82c 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -691,6 +691,29 @@ out:
691 691
692static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store); 692static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store);
693 693
694static void firmware_rw(struct firmware_buf *buf, char *buffer,
695 loff_t offset, size_t count, bool read)
696{
697 while (count) {
698 void *page_data;
699 int page_nr = offset >> PAGE_SHIFT;
700 int page_ofs = offset & (PAGE_SIZE-1);
701 int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
702
703 page_data = kmap(buf->pages[page_nr]);
704
705 if (read)
706 memcpy(buffer, page_data + page_ofs, page_cnt);
707 else
708 memcpy(page_data + page_ofs, buffer, page_cnt);
709
710 kunmap(buf->pages[page_nr]);
711 buffer += page_cnt;
712 offset += page_cnt;
713 count -= page_cnt;
714 }
715}
716
694static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj, 717static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj,
695 struct bin_attribute *bin_attr, 718 struct bin_attribute *bin_attr,
696 char *buffer, loff_t offset, size_t count) 719 char *buffer, loff_t offset, size_t count)
@@ -715,21 +738,8 @@ static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj,
715 738
716 ret_count = count; 739 ret_count = count;
717 740
718 while (count) { 741 firmware_rw(buf, buffer, offset, count, true);
719 void *page_data;
720 int page_nr = offset >> PAGE_SHIFT;
721 int page_ofs = offset & (PAGE_SIZE-1);
722 int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
723
724 page_data = kmap(buf->pages[page_nr]);
725
726 memcpy(buffer, page_data + page_ofs, page_cnt);
727 742
728 kunmap(buf->pages[page_nr]);
729 buffer += page_cnt;
730 offset += page_cnt;
731 count -= page_cnt;
732 }
733out: 743out:
734 mutex_unlock(&fw_lock); 744 mutex_unlock(&fw_lock);
735 return ret_count; 745 return ret_count;
@@ -809,24 +819,9 @@ static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj,
809 goto out; 819 goto out;
810 820
811 retval = count; 821 retval = count;
822 firmware_rw(buf, buffer, offset, count, false);
812 823
813 while (count) { 824 buf->size = max_t(size_t, offset + count, buf->size);
814 void *page_data;
815 int page_nr = offset >> PAGE_SHIFT;
816 int page_ofs = offset & (PAGE_SIZE - 1);
817 int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
818
819 page_data = kmap(buf->pages[page_nr]);
820
821 memcpy(page_data + page_ofs, buffer, page_cnt);
822
823 kunmap(buf->pages[page_nr]);
824 buffer += page_cnt;
825 offset += page_cnt;
826 count -= page_cnt;
827 }
828
829 buf->size = max_t(size_t, offset, buf->size);
830out: 825out:
831 mutex_unlock(&fw_lock); 826 mutex_unlock(&fw_lock);
832 return retval; 827 return retval;